diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index e281c5ea..27db68de 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -4,7 +4,7 @@ gwen: pp: 6a32b9b wpa: 743c778 espnow: 743c778 - wps: 743c778 + wps: 866fcf9 smartconfig: 2.8.2 phy: 1149 diff --git a/components/esp8266/lib/libwps.a b/components/esp8266/lib/libwps.a old mode 100644 new mode 100755 diff --git a/components/esp8266/lib/libwps_dbg.a b/components/esp8266/lib/libwps_dbg.a old mode 100644 new mode 100755 diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index e96638fb..ca60c9ed 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -1,4 +1,4 @@ -set(COMPONENT_SRCDIRS "src/crypto" "port") +set(COMPONENT_SRCDIRS "src/crypto" "src/wps" "port") set(COMPONENT_ADD_INCLUDEDIRS "include" "port/include") set(COMPONENT_PRIV_REQUIRES "freertos" "heap" "newlib" "util") @@ -10,4 +10,7 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE __ets__ EMBEDDED_SUPP ESPRESSIF_USE + CONFIG_WPS2 + CONFIG_WPS_PIN + USE_WPS_TASK ) diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index ee92a861..6f1de983 100644 --- a/components/wpa_supplicant/component.mk +++ b/components/wpa_supplicant/component.mk @@ -1,4 +1,4 @@ COMPONENT_ADD_INCLUDEDIRS := include port/include -COMPONENT_SRCDIRS := src/crypto port +COMPONENT_SRCDIRS := src/crypto src/wps port -CFLAGS += -DEMBEDDED_SUPP -D__ets__ -DESPRESSIF_USE \ No newline at end of file +CFLAGS += -DEMBEDDED_SUPP -D__ets__ -DESPRESSIF_USE -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -Wno-unused-but-set-variable -Wno-empty-body \ No newline at end of file diff --git a/components/wpa_supplicant/include/eap/eap_common.h b/components/wpa_supplicant/include/eap/eap_common.h new file mode 100755 index 00000000..38c57100 --- /dev/null +++ b/components/wpa_supplicant/include/eap/eap_common.h @@ -0,0 +1,23 @@ +/* + * EAP common peer/server definitions + * Copyright (c) 2004-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_COMMON_H +#define EAP_COMMON_H + +#include "wpa/wpabuf.h" + +int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload); +const u8 * eap_hdr_validate(int vendor, EapType eap_type, + const struct wpabuf *msg, size_t *plen); +struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, + u8 code, u8 identifier); +void eap_update_len(struct wpabuf *msg); +u8 eap_get_id(const struct wpabuf *msg); +EapType eap_get_type(const struct wpabuf *msg); + +#endif /* EAP_COMMON_H */ diff --git a/components/wpa_supplicant/include/eap/eap_defs.h b/components/wpa_supplicant/include/eap/eap_defs.h new file mode 100755 index 00000000..10995d38 --- /dev/null +++ b/components/wpa_supplicant/include/eap/eap_defs.h @@ -0,0 +1,92 @@ +/* + * EAP server/peer: Shared EAP definitions + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_DEFS_H +#define EAP_DEFS_H + +/* RFC 3748 - Extensible Authentication Protocol (EAP) */ + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_hdr { + u8 code; + u8 identifier; + be16 length; /* including code and identifier; network byte order */ + /* followed by length-4 octets of data */ +} STRUCT_PACKED; + + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3, + EAP_CODE_FAILURE = 4 }; + +/* EAP Request and Response data begins with one octet Type. Success and + * Failure do not have additional data. */ + +/* + * EAP Method Types as allocated by IANA: + * http://www.iana.org/assignments/eap-numbers + */ +typedef enum { + EAP_TYPE_NONE = 0, + EAP_TYPE_IDENTITY = 1 /* RFC 3748 */, + EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */, + EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */, + EAP_TYPE_MD5 = 4, /* RFC 3748 */ + EAP_TYPE_OTP = 5 /* RFC 3748 */, + EAP_TYPE_GTC = 6, /* RFC 3748 */ + EAP_TYPE_TLS = 13 /* RFC 2716 */, + EAP_TYPE_LEAP = 17 /* Cisco proprietary */, + EAP_TYPE_SIM = 18 /* RFC 4186 */, + EAP_TYPE_TTLS = 21 /* RFC 5281 */, + EAP_TYPE_AKA = 23 /* RFC 4187 */, + EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */, + EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */, + EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */, + EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment; + * type 38 has previously been allocated for + * EAP-HTTP Digest, (funk.com) */, + EAP_TYPE_FAST = 43 /* RFC 4851 */, + EAP_TYPE_PAX = 46 /* RFC 4746 */, + EAP_TYPE_PSK = 47 /* RFC 4764 */, + EAP_TYPE_SAKE = 48 /* RFC 4763 */, + EAP_TYPE_IKEV2 = 49 /* RFC 5106 */, + EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */, + EAP_TYPE_GPSK = 51 /* RFC 5433 */, + EAP_TYPE_PWD = 52 /* RFC 5931 */, + EAP_TYPE_EKE = 53 /* RFC 6124 */, + EAP_TYPE_EXPANDED = 254 /* RFC 3748 */ +} EapType; + + +/* SMI Network Management Private Enterprise Code for vendor specific types */ +enum { + EAP_VENDOR_IETF = 0, + EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */, + EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */, + EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */ +}; + +struct eap_expand { + u8 vendor_id[3]; + be32 vendor_type; + u8 opcode; +} STRUCT_PACKED; + +#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP +#define EAP_VENDOR_TYPE_UNAUTH_TLS 1 + +#define EAP_MSK_LEN 64 +#define EAP_EMSK_LEN 64 + +#endif /* EAP_DEFS_H */ diff --git a/components/wpa_supplicant/include/wpa/ap_config.h b/components/wpa_supplicant/include/wpa/ap_config.h new file mode 100755 index 00000000..761becb4 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/ap_config.h @@ -0,0 +1,544 @@ +/* + * hostapd / Configuration definitions and helpers functions + * Copyright (c) 2003-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef HOSTAPD_CONFIG_H +#define HOSTAPD_CONFIG_H + +#include "wpa/defs.h" +//#include "ip_addr.h" +#include "wpa/wpa_common.h" +//#include "common/ieee802_11_common.h" +//#include "wps/wps.h" + +#define MAX_STA_COUNT 4 +#define MAX_VLAN_ID 4094 + +typedef u8 macaddr[ETH_ALEN]; + +struct mac_acl_entry { + macaddr addr; + int vlan_id; +}; + +struct hostapd_radius_servers; +struct ft_remote_r0kh; +struct ft_remote_r1kh; + +#define HOSTAPD_MAX_SSID_LEN 32 + +#define NUM_WEP_KEYS 4 +struct hostapd_wep_keys { + u8 idx; + u8 *key[NUM_WEP_KEYS]; + size_t len[NUM_WEP_KEYS]; + int keys_set; + size_t default_len; /* key length used for dynamic key generation */ +}; + +typedef enum hostap_security_policy { + SECURITY_PLAINTEXT = 0, + SECURITY_STATIC_WEP = 1, + SECURITY_IEEE_802_1X = 2, + SECURITY_WPA_PSK = 3, + SECURITY_WPA = 4 +} secpolicy; + +struct hostapd_ssid { + u8 ssid[HOSTAPD_MAX_SSID_LEN]; + size_t ssid_len; + unsigned int ssid_set:1; + unsigned int utf8_ssid:1; + +// char vlan[IFNAMSIZ + 1]; +// secpolicy security_policy; + + struct hostapd_wpa_psk *wpa_psk; + char *wpa_passphrase; +// char *wpa_psk_file; + + struct hostapd_wep_keys wep; + +#if 0 +#define DYNAMIC_VLAN_DISABLED 0 +#define DYNAMIC_VLAN_OPTIONAL 1 +#define DYNAMIC_VLAN_REQUIRED 2 + int dynamic_vlan; +#define DYNAMIC_VLAN_NAMING_WITHOUT_DEVICE 0 +#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1 +#define DYNAMIC_VLAN_NAMING_END 2 + int vlan_naming; +#ifdef CONFIG_FULL_DYNAMIC_VLAN + char *vlan_tagged_interface; +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ + struct hostapd_wep_keys **dyn_vlan_keys; + size_t max_dyn_vlan_keys; +#endif +}; + +#if 0 +#define VLAN_ID_WILDCARD -1 + +struct hostapd_vlan { + struct hostapd_vlan *next; + int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */ + char ifname[IFNAMSIZ + 1]; + int dynamic_vlan; +#ifdef CONFIG_FULL_DYNAMIC_VLAN + +#define DVLAN_CLEAN_BR 0x1 +#define DVLAN_CLEAN_VLAN 0x2 +#define DVLAN_CLEAN_VLAN_PORT 0x4 +#define DVLAN_CLEAN_WLAN_PORT 0x8 + int clean; +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ +}; +#endif + +#define PMK_LEN 32 +struct hostapd_sta_wpa_psk_short { + struct hostapd_sta_wpa_psk_short *next; + u8 psk[PMK_LEN]; +}; + +struct hostapd_wpa_psk { + struct hostapd_wpa_psk *next; + int group; + u8 psk[PMK_LEN]; + u8 addr[ETH_ALEN]; +}; + +#if 0 +struct hostapd_eap_user { + struct hostapd_eap_user *next; + u8 *identity; + size_t identity_len; + struct { + int vendor; + u32 method; + } methods[EAP_MAX_METHODS]; + u8 *password; + size_t password_len; + int phase2; + int force_version; + unsigned int wildcard_prefix:1; + unsigned int password_hash:1; /* whether password is hashed with + * nt_password_hash() */ + int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */ +}; + +struct hostapd_radius_attr { + u8 type; + struct wpabuf *val; + struct hostapd_radius_attr *next; +}; + + +#define NUM_TX_QUEUES 4 + +struct hostapd_tx_queue_params { + int aifs; + int cwmin; + int cwmax; + int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */ +}; + + +#define MAX_ROAMING_CONSORTIUM_LEN 15 + +struct hostapd_roaming_consortium { + u8 len; + u8 oi[MAX_ROAMING_CONSORTIUM_LEN]; +}; + +struct hostapd_lang_string { + u8 lang[3]; + u8 name_len; + u8 name[252]; +}; + +#define MAX_NAI_REALMS 10 +#define MAX_NAI_REALMLEN 255 +#define MAX_NAI_EAP_METHODS 5 +#define MAX_NAI_AUTH_TYPES 4 +struct hostapd_nai_realm_data { + u8 encoding; + char realm_buf[MAX_NAI_REALMLEN + 1]; + char *realm[MAX_NAI_REALMS]; + u8 eap_method_count; + struct hostapd_nai_realm_eap { + u8 eap_method; + u8 num_auths; + u8 auth_id[MAX_NAI_AUTH_TYPES]; + u8 auth_val[MAX_NAI_AUTH_TYPES]; + } eap_method[MAX_NAI_EAP_METHODS]; +}; +#endif + +/** + * struct hostapd_bss_config - Per-BSS configuration + */ +struct hostapd_bss_config { +// char iface[IFNAMSIZ + 1]; +// char bridge[IFNAMSIZ + 1]; +// char wds_bridge[IFNAMSIZ + 1]; + +// enum hostapd_logger_level logger_syslog_level, logger_stdout_level; + +// unsigned int logger_syslog; /* module bitfield */ +// unsigned int logger_stdout; /* module bitfield */ + +// char *dump_log_name; /* file name for state dump (SIGUSR1) */ + + int max_num_sta; /* maximum number of STAs in station table */ + + int dtim_period; + + int ieee802_1x; /* use IEEE 802.1X */ + int eapol_version; +// int eap_server; /* Use internal EAP server instead of external +// * RADIUS server */ +// struct hostapd_eap_user *eap_user; +// char *eap_user_sqlite; +// char *eap_sim_db; +// struct hostapd_ip_addr own_ip_addr; +// char *nas_identifier; +// struct hostapd_radius_servers *radius; +// int acct_interim_interval; +// int radius_request_cui; +// struct hostapd_radius_attr *radius_auth_req_attr; +// struct hostapd_radius_attr *radius_acct_req_attr; +// int radius_das_port; +// unsigned int radius_das_time_window; +// int radius_das_require_event_timestamp; +// struct hostapd_ip_addr radius_das_client_addr; +// u8 *radius_das_shared_secret; +// size_t radius_das_shared_secret_len; + + struct hostapd_ssid ssid; + +// char *eap_req_id_text; /* optional displayable message sent with +// * EAP Request-Identity */ +// size_t eap_req_id_text_len; +// int eapol_key_index_workaround; + +// size_t default_wep_key_len; +// int individual_wep_key_len; + int wep_rekeying_period; + int broadcast_key_idx_min, broadcast_key_idx_max; +// int eap_reauth_period; + +// int ieee802_11f; /* use IEEE 802.11f (IAPP) */ +// char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast +// * frames */ + + enum { + ACCEPT_UNLESS_DENIED = 0, + DENY_UNLESS_ACCEPTED = 1, + USE_EXTERNAL_RADIUS_AUTH = 2 + } macaddr_acl; +// struct mac_acl_entry *accept_mac; +// int num_accept_mac; +// struct mac_acl_entry *deny_mac; +// int num_deny_mac; +// int wds_sta; +// int isolate; + + int auth_algs; /* bitfield of allowed IEEE 802.11 authentication + * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ + + int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */ + int wpa_key_mgmt; +#ifdef CONFIG_IEEE80211W + enum mfp_options ieee80211w; + /* dot11AssociationSAQueryMaximumTimeout (in TUs) */ + unsigned int assoc_sa_query_max_timeout; + /* dot11AssociationSAQueryRetryTimeout (in TUs) */ + int assoc_sa_query_retry_timeout; +#endif /* CONFIG_IEEE80211W */ + enum { + PSK_RADIUS_IGNORED = 0, + PSK_RADIUS_ACCEPTED = 1, + PSK_RADIUS_REQUIRED = 2 + } wpa_psk_radius; + int wpa_pairwise; + int wpa_group; + int wpa_group_rekey; + int wpa_strict_rekey; + int wpa_gmk_rekey; + int wpa_ptk_rekey; + int rsn_pairwise; + int rsn_preauth; + char *rsn_preauth_interfaces; + int peerkey; + +#ifdef CONFIG_IEEE80211R + /* IEEE 802.11r - Fast BSS Transition */ + u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; + u8 r1_key_holder[FT_R1KH_ID_LEN]; + u32 r0_key_lifetime; + u32 reassociation_deadline; + struct ft_remote_r0kh *r0kh_list; + struct ft_remote_r1kh *r1kh_list; + int pmk_r1_push; + int ft_over_ds; +#endif /* CONFIG_IEEE80211R */ + +// char *ctrl_interface; /* directory for UNIX domain sockets */ +#ifndef CONFIG_NATIVE_WINDOWS +// gid_t ctrl_interface_gid; +#endif /* CONFIG_NATIVE_WINDOWS */ +// int ctrl_interface_gid_set; + +// char *ca_cert; +// char *server_cert; +// char *private_key; +// char *private_key_passwd; +// int check_crl; +// char *dh_file; +// u8 *pac_opaque_encr_key; +// u8 *eap_fast_a_id; +// size_t eap_fast_a_id_len; +// char *eap_fast_a_id_info; +// int eap_fast_prov; +// int pac_key_lifetime; +// int pac_key_refresh_time; +// int eap_sim_aka_result_ind; +// int tnc; +// int fragment_size; +// u16 pwd_group; + +// char *radius_server_clients; +// int radius_server_auth_port; +// int radius_server_ipv6; + +// char *test_socket; /* UNIX domain socket path for driver_test */ + +// int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group +// * address instead of individual address +// * (for driver_wired.c). +// */ + + int ap_max_inactivity; + int ignore_broadcast_ssid; + + int wmm_enabled; + int wmm_uapsd; + +// struct hostapd_vlan *vlan, *vlan_tail; + + macaddr bssid; + + /* + * Maximum listen interval that STAs can use when associating with this + * BSS. If a STA tries to use larger value, the association will be + * denied with status code 51. + */ + u16 max_listen_interval; + +// int disable_pmksa_caching; +// int okc; /* Opportunistic Key Caching */ + +// int wps_state; +#ifdef CONFIG_WPS + int ap_setup_locked; + u8 uuid[16]; + char *wps_pin_requests; + char *device_name; + char *manufacturer; + char *model_name; + char *model_number; + char *serial_number; + u8 device_type[WPS_DEV_TYPE_LEN]; + char *config_methods; + u8 os_version[4]; + char *ap_pin; + int skip_cred_build; + u8 *extra_cred; + size_t extra_cred_len; + int wps_cred_processing; + u8 *ap_settings; + size_t ap_settings_len; + char *upnp_iface; + char *friendly_name; + char *manufacturer_url; + char *model_description; + char *model_url; + char *upc; + struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; + int wps_nfc_dev_pw_id; + struct wpabuf *wps_nfc_dh_pubkey; + struct wpabuf *wps_nfc_dh_privkey; + struct wpabuf *wps_nfc_dev_pw; +#endif /* CONFIG_WPS */ +// int pbc_in_m1; + +#define P2P_ENABLED BIT(0) +#define P2P_GROUP_OWNER BIT(1) +#define P2P_GROUP_FORMATION BIT(2) +#define P2P_MANAGE BIT(3) +#define P2P_ALLOW_CROSS_CONNECTION BIT(4) +// int p2p; + +// int disassoc_low_ack; +// int skip_inactivity_poll; + +#define TDLS_PROHIBIT BIT(0) +#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1) +// int tdls; +// int disable_11n; +// int disable_11ac; + + /* IEEE 802.11v */ +// int time_advertisement; +// char *time_zone; +// int wnm_sleep_mode; +// int bss_transition; + + /* IEEE 802.11u - Interworking */ +// int interworking; +// int access_network_type; +// int internet; +// int asra; +// int esr; +// int uesa; +// int venue_info_set; +// u8 venue_group; +// u8 venue_type; +// u8 hessid[ETH_ALEN]; + + /* IEEE 802.11u - Roaming Consortium list */ +// unsigned int roaming_consortium_count; +// struct hostapd_roaming_consortium *roaming_consortium; + + /* IEEE 802.11u - Venue Name duples */ +// unsigned int venue_name_count; +// struct hostapd_lang_string *venue_name; + + /* IEEE 802.11u - Network Authentication Type */ +// u8 *network_auth_type; +// size_t network_auth_type_len; + + /* IEEE 802.11u - IP Address Type Availability */ +// u8 ipaddr_type_availability; +// u8 ipaddr_type_configured; + + /* IEEE 802.11u - 3GPP Cellular Network */ +// u8 *anqp_3gpp_cell_net; +// size_t anqp_3gpp_cell_net_len; + + /* IEEE 802.11u - Domain Name */ +// u8 *domain_name; +// size_t domain_name_len; + +// unsigned int nai_realm_count; +// struct hostapd_nai_realm_data *nai_realm_data; + +// u16 gas_comeback_delay; +// int gas_frag_limit; + +#ifdef CONFIG_HS20 + int hs20; + int disable_dgaf; + unsigned int hs20_oper_friendly_name_count; + struct hostapd_lang_string *hs20_oper_friendly_name; + u8 *hs20_wan_metrics; + u8 *hs20_connection_capability; + size_t hs20_connection_capability_len; + u8 *hs20_operating_class; + u8 hs20_operating_class_len; +#endif /* CONFIG_HS20 */ + +// u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */ + +#ifdef CONFIG_RADIUS_TEST + char *dump_msk_file; +#endif /* CONFIG_RADIUS_TEST */ + +// struct wpabuf *vendor_elements; +}; + + +/** + * struct hostapd_config - Per-radio interface configuration + */ +struct hostapd_config { + struct hostapd_bss_config *bss, *last_bss; + size_t num_bss; + + u16 beacon_int; + int rts_threshold; + int fragm_threshold; + u8 send_probe_response; + u8 channel; + enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ + enum { + LONG_PREAMBLE = 0, + SHORT_PREAMBLE = 1 + } preamble; + + int *supported_rates; + int *basic_rates; + + const struct wpa_driver_ops *driver; + + int ap_table_max_size; + int ap_table_expiration_time; + + char country[3]; /* first two octets: country code as described in + * ISO/IEC 3166-1. Third octet: + * ' ' (ascii 32): all environments + * 'O': Outdoor environemnt only + * 'I': Indoor environment only + */ + + int ieee80211d; + +// struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES]; + + /* + * WMM AC parameters, in same order as 802.1D, i.e. + * 0 = BE (best effort) + * 1 = BK (background) + * 2 = VI (video) + * 3 = VO (voice) + */ +// struct hostapd_wmm_ac_params wmm_ac_params[4]; + + int ht_op_mode_fixed; + u16 ht_capab; + int ieee80211n; + int secondary_channel; + int require_ht; + u32 vht_capab; + int ieee80211ac; + int require_vht; + u8 vht_oper_chwidth; + u8 vht_oper_centr_freq_seg0_idx; + u8 vht_oper_centr_freq_seg1_idx; +}; + + +int hostapd_mac_comp(const void *a, const void *b); +int hostapd_mac_comp_empty(const void *a); +struct hostapd_config * hostapd_config_defaults(void); +void hostapd_config_defaults_bss(struct hostapd_bss_config *bss); +void hostapd_config_free(struct hostapd_config *conf); +int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, + const u8 *addr, int *vlan_id); +int hostapd_rate_found(int *list, int rate); +int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, + struct hostapd_wep_keys *b); +const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, + const u8 *addr, const u8 *prev_psk); +int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf); +//const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, +// int vlan_id); +//struct hostapd_radius_attr * +//hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type); + +#endif /* HOSTAPD_CONFIG_H */ diff --git a/components/wpa_supplicant/include/wpa/common.h b/components/wpa_supplicant/include/wpa/common.h new file mode 100755 index 00000000..97d72fed --- /dev/null +++ b/components/wpa_supplicant/include/wpa/common.h @@ -0,0 +1,337 @@ +/* + * wpa_supplicant/hostapd / common helper functions, etc. + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef COMMON_H +#define COMMON_H + +#if defined(__ets__) +#endif /* ets */ +#include "os.h" + +#if defined(__XTENSA__) +#include +#define __BYTE_ORDER BYTE_ORDER +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#endif /*__XTENSA__*/ + +#if defined(__ets__) +//#include "c_types.h" +#include +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +typedef int64_t s64; +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; +#endif /* ets */ + +#if defined(__linux__) || defined(__GLIBC__) || defined(__ets__) +#include +#include +#endif /* __linux__ */ + +/* Define platform specific byte swapping macros */ + +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) + +static inline unsigned short wpa_swap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int wpa_swap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} + +#define le_to_host16(n) (n) +#define host_to_le16(n) (n) +#define be_to_host16(n) wpa_swap_16(n) +#define host_to_be16(n) wpa_swap_16(n) +#define le_to_host32(n) (n) +#define be_to_host32(n) wpa_swap_32(n) +#define host_to_be32(n) wpa_swap_32(n) + +#define WPA_BYTE_SWAP_DEFINED + +#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ + + +#ifndef WPA_BYTE_SWAP_DEFINED + +#ifndef __BYTE_ORDER +#ifndef __LITTLE_ENDIAN +#ifndef __BIG_ENDIAN +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#if defined(sparc) +#define __BYTE_ORDER __BIG_ENDIAN +#endif +#endif /* __BIG_ENDIAN */ +#endif /* __LITTLE_ENDIAN */ +#endif /* __BYTE_ORDER */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define le_to_host16(n) ((__force u16) (le16) (n)) +#define host_to_le16(n) ((__force le16) (u16) (n)) +#define be_to_host16(n) __bswap_16((__force u16) (be16) (n)) +#define host_to_be16(n) ((__force be16) __bswap_16((n))) +#define le_to_host32(n) ((__force u32) (le32) (n)) +#define host_to_le32(n) ((__force le32) (u32) (n)) +#define be_to_host32(n) __bswap_32((__force u32) (be32) (n)) +#define host_to_be32(n) ((__force be32) __bswap_32((n))) +#define le_to_host64(n) ((__force u64) (le64) (n)) +#define host_to_le64(n) ((__force le64) (u64) (n)) +#define be_to_host64(n) __bswap_64((__force u64) (be64) (n)) +#define host_to_be64(n) ((__force be64) bswap_64((n))) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define le_to_host16(n) __bswap_16(n) +#define host_to_le16(n) __bswap_16(n) +#define be_to_host16(n) (n) +#define host_to_be16(n) (n) +#define le_to_host32(n) __bswap_32(n) +#define be_to_host32(n) (n) +#define host_to_be32(n) (n) +#define le_to_host64(n) __bswap_64(n) +#define host_to_le64(n) __bswap_64(n) +#define be_to_host64(n) (n) +#define host_to_be64(n) (n) +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#endif +#else +#error Could not determine CPU byte order +#endif + +#define WPA_BYTE_SWAP_DEFINED +#endif /* !WPA_BYTE_SWAP_DEFINED */ + + +/* Macros for handling unaligned memory accesses */ + +#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) +#define WPA_PUT_BE16(a, val) \ + do { \ + (a)[0] = ((u16) (val)) >> 8; \ + (a)[1] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) +#define WPA_PUT_LE16(a, val) \ + do { \ + (a)[1] = ((u16) (val)) >> 8; \ + (a)[0] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ + ((u32) (a)[2])) +#define WPA_PUT_BE24(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[2] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ + (((u32) (a)[2]) << 8) | ((u32) (a)[3])) +#define WPA_PUT_BE32(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[3] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ + (((u32) (a)[1]) << 8) | ((u32) (a)[0])) +#define WPA_PUT_LE32(a, val) \ + do { \ + (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[0] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ + (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ + (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ + (((u64) (a)[6]) << 8) | ((u64) (a)[7])) +#define WPA_PUT_BE64(a, val) \ + do { \ + (a)[0] = (u8) (((u64) (val)) >> 56); \ + (a)[1] = (u8) (((u64) (val)) >> 48); \ + (a)[2] = (u8) (((u64) (val)) >> 40); \ + (a)[3] = (u8) (((u64) (val)) >> 32); \ + (a)[4] = (u8) (((u64) (val)) >> 24); \ + (a)[5] = (u8) (((u64) (val)) >> 16); \ + (a)[6] = (u8) (((u64) (val)) >> 8); \ + (a)[7] = (u8) (((u64) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ + (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ + (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ + (((u64) (a)[1]) << 8) | ((u64) (a)[0])) + + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif +//#ifndef IFNAMSIZ +//#define IFNAMSIZ 16 +//#endif +#ifndef ETH_P_ALL +#define ETH_P_ALL 0x0003 +#endif +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ +#ifndef ETH_P_EAPOL +#define ETH_P_EAPOL ETH_P_PAE +#endif /* ETH_P_EAPOL */ +#ifndef ETH_P_RSN_PREAUTH +#define ETH_P_RSN_PREAUTH 0x88c7 +#endif /* ETH_P_RSN_PREAUTH */ +#ifndef ETH_P_RRB +#define ETH_P_RRB 0x890D +#endif /* ETH_P_RRB */ + + +#ifdef __GNUC__ +#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) +#define STRUCT_PACKED __attribute__ ((packed)) +#else +#define PRINTF_FORMAT(a,b) +#define STRUCT_PACKED +#endif + +#ifdef CONFIG_ANSI_C_EXTRA + +/* inline - define as __inline or just define it to be empty, if needed */ +#ifdef CONFIG_NO_INLINE +#define inline +#else +#define inline __inline +#endif + +#ifndef __func__ +#define __func__ "__func__ not defined" +#endif + +#ifndef bswap_16 +#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) +#endif + +#ifndef bswap_32 +#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ + (((u32) (a) << 8) & 0xff0000) | \ + (((u32) (a) >> 8) & 0xff00) | \ + (((u32) (a) >> 24) & 0xff)) +#endif + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif + +#ifdef _WIN32_WCE +void perror(const char *s); +#endif /* _WIN32_WCE */ + +#endif /* CONFIG_ANSI_C_EXTRA */ + +#ifndef MAC2STR +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" +#endif + +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif + +/* + * Definitions for sparse validation + * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) + */ +#ifdef __CHECKER__ +#define __force __attribute__((force)) +#define __bitwise __attribute__((bitwise)) +#else +#define __force +#define __bitwise +#endif + +typedef u16 __bitwise be16; +typedef u16 __bitwise le16; +typedef u32 __bitwise be32; +typedef u32 __bitwise le32; +typedef u64 __bitwise be64; +typedef u64 __bitwise le64; + +#ifndef __must_check +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __must_check __attribute__((__warn_unused_result__)) +#else +#define __must_check +#endif /* __GNUC__ */ +#endif /* __must_check */ + +int hwaddr_aton(const char *txt, u8 *addr); +int hwaddr_aton2(const char *txt, u8 *addr); +int hexstr2bin(const char *hex, u8 *buf, size_t len); +void inc_byte_array(u8 *counter, size_t len); +void wpa_get_ntp_timestamp(u8 *buf); +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len); + +#ifdef CONFIG_NATIVE_WINDOWS +void wpa_unicode2ascii_inplace(TCHAR *str); +TCHAR * wpa_strdup_tchar(const char *str); +#else /* CONFIG_NATIVE_WINDOWS */ +#define wpa_unicode2ascii_inplace(s) do { } while (0) +#define wpa_strdup_tchar(s) strdup((s)) +#endif /* CONFIG_NATIVE_WINDOWS */ + +const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); +char * wpa_config_parse_string(const char *value, size_t *len); + +static inline int is_zero_ether_addr(const u8 *a) +{ + return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); +} + +extern const struct eth_addr ethbroadcast; +#define broadcast_ether_addr ðbroadcast + +#include "wpabuf.h" +#include "wpa_debug.h" + + +/* + * gcc 4.4 ends up generating strict-aliasing warnings about some very common + * networking socket uses that do not really result in a real problem and + * cannot be easily avoided with union-based type-punning due to struct + * definitions including another struct in system header files. To avoid having + * to fully disable strict-aliasing warnings, provide a mechanism to hide the + * typecast from aliasing for now. A cleaner solution will hopefully be found + * in the future to handle these cases. + */ +void * __hide_aliasing_typecast(void *foo); +#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) + +#endif /* COMMON_H */ diff --git a/components/wpa_supplicant/include/wpa/defs.h b/components/wpa_supplicant/include/wpa/defs.h new file mode 100755 index 00000000..f019cee9 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/defs.h @@ -0,0 +1,307 @@ +/* + * WPA Supplicant - Common definitions + * Copyright (c) 2004-2008, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef DEFS_H +#define DEFS_H + +#ifdef FALSE +#undef FALSE +#endif +#ifdef TRUE +#undef TRUE +#endif +typedef enum { FALSE = 0, TRUE = 1 } Boolean; + +/* +#define WPA_CIPHER_NONE BIT(0) +#define WPA_CIPHER_WEP40 BIT(1) +#define WPA_CIPHER_WEP104 BIT(2) +#define WPA_CIPHER_TKIP BIT(3) +#define WPA_CIPHER_CCMP BIT(4) +#ifdef CONFIG_IEEE80211W +#define WPA_CIPHER_AES_128_CMAC BIT(5) +#endif +*/ + +/* + * NB: these values are ordered carefully; there are lots of + * of implications in any reordering. Beware that 4 is used + * only to indicate h/w TKIP MIC support in driver capabilities; + * there is no separate cipher support (it's rolled into the + * TKIP cipher support). + */ +#define IEEE80211_CIPHER_NONE 0 /* pseudo value */ +#define IEEE80211_CIPHER_TKIP 1 +#define IEEE80211_CIPHER_AES_OCB 2 +#define IEEE80211_CIPHER_AES_CCM 3 +#define IEEE80211_CIPHER_TKIPMIC 4 /* TKIP MIC capability */ +#define IEEE80211_CIPHER_CKIP 5 +#define IEEE80211_CIPHER_WEP 6 +#define IEEE80211_CIPHER_WEP40 7 +#define IEEE80211_CIPHER_WEP104 8 + + +#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+2) + +/* capability bits in ic_cryptocaps/iv_cryptocaps */ +#define IEEE80211_CRYPTO_NONE (1<wpa_state). The current state can be retrieved with + * wpa_supplicant_get_state() function and the state can be changed by calling + * wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the + * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used + * to access the state variable. + */ +enum wpa_states { + /** + * WPA_DISCONNECTED - Disconnected state + * + * This state indicates that client is not associated, but is likely to + * start looking for an access point. This state is entered when a + * connection is lost. + */ + WPA_DISCONNECTED, + + /** + * WPA_INACTIVE - Inactive state (wpa_supplicant disabled) + * + * This state is entered if there are no enabled networks in the + * configuration. wpa_supplicant is not trying to associate with a new + * network and external interaction (e.g., ctrl_iface call to add or + * enable a network) is needed to start association. + */ + WPA_INACTIVE, + + /** + * WPA_SCANNING - Scanning for a network + * + * This state is entered when wpa_supplicant starts scanning for a + * network. + */ + WPA_SCANNING, + + /** + * WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID + * + * This state is entered when wpa_supplicant has found a suitable BSS + * to authenticate with and the driver is configured to try to + * authenticate with this BSS. This state is used only with drivers + * that use wpa_supplicant as the SME. + */ + WPA_AUTHENTICATING, + + /** + * WPA_ASSOCIATING - Trying to associate with a BSS/SSID + * + * This state is entered when wpa_supplicant has found a suitable BSS + * to associate with and the driver is configured to try to associate + * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this + * state is entered when the driver is configured to try to associate + * with a network using the configured SSID and security policy. + */ + WPA_ASSOCIATING, + + /** + * WPA_ASSOCIATED - Association completed + * + * This state is entered when the driver reports that association has + * been successfully completed with an AP. If IEEE 802.1X is used + * (with or without WPA/WPA2), wpa_supplicant remains in this state + * until the IEEE 802.1X/EAPOL authentication has been completed. + */ + WPA_ASSOCIATED, + + /** + * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress + * + * This state is entered when WPA/WPA2 4-Way Handshake is started. In + * case of WPA-PSK, this happens when receiving the first EAPOL-Key + * frame after association. In case of WPA-EAP, this state is entered + * when the IEEE 802.1X/EAPOL authentication has been completed. + */ + WPA_FIRST_HALF_4WAY_HANDSHAKE, + + WPA_LAST_HALF_4WAY_HANDSHAKE, + + /** + * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress + * + * This state is entered when 4-Way Key Handshake has been completed + * (i.e., when the supplicant sends out message 4/4) and when Group + * Key rekeying is started by the AP (i.e., when supplicant receives + * message 1/2). + */ + WPA_GROUP_HANDSHAKE, + + /** + * WPA_COMPLETED - All authentication completed + * + * This state is entered when the full authentication process is + * completed. In case of WPA2, this happens when the 4-Way Handshake is + * successfully completed. With WPA, this state is entered after the + * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is + * completed after dynamic keys are received (or if not used, after + * the EAP authentication has been completed). With static WEP keys and + * plaintext connections, this state is entered when an association + * has been completed. + * + * This state indicates that the supplicant has completed its + * processing for the association phase and that data connection is + * fully configured. + */ + WPA_COMPLETED, + + WPA_MIC_FAILURE, // first mic_error event occur + + WPA_TKIP_COUNTERMEASURES //in countermeasure period that stop connect with ap in 60 sec +}; + +#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0 +#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1 +#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2 +#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3 + +#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0 +#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1 + +/** + * enum hostapd_hw_mode - Hardware mode + */ +enum hostapd_hw_mode { + HOSTAPD_MODE_IEEE80211B, + HOSTAPD_MODE_IEEE80211G, + HOSTAPD_MODE_IEEE80211A, + HOSTAPD_MODE_IEEE80211AD, + NUM_HOSTAPD_MODES +}; + +#endif /* DEFS_H */ diff --git a/components/wpa_supplicant/include/wpa/eapol_common.h b/components/wpa_supplicant/include/wpa/eapol_common.h new file mode 100755 index 00000000..6a40ac33 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/eapol_common.h @@ -0,0 +1,71 @@ +/* + * EAPOL definitions shared between hostapd and wpa_supplicant + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef EAPOL_COMMON_H +#define EAPOL_COMMON_H + +/* IEEE Std 802.1X-2004 */ + +struct ieee802_1x_hdr { + u8 version; + u8 type; + be16 length; + /* followed by length octets of data */ +} STRUCT_PACKED; + + +#define EAPOL_VERSION 2 + +enum { IEEE802_1X_TYPE_EAP_PACKET = 0, + IEEE802_1X_TYPE_EAPOL_START = 1, + IEEE802_1X_TYPE_EAPOL_LOGOFF = 2, + IEEE802_1X_TYPE_EAPOL_KEY = 3, + IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4 +}; + +enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2, + EAPOL_KEY_TYPE_WPA = 254 }; + +#define IEEE8021X_REPLAY_COUNTER_LEN 8 +#define IEEE8021X_KEY_SIGN_LEN 16 +#define IEEE8021X_KEY_IV_LEN 16 + +#define IEEE8021X_KEY_INDEX_FLAG 0x80 +#define IEEE8021X_KEY_INDEX_MASK 0x03 + +struct ieee802_1x_eapol_key { + u8 type; + /* Note: key_length is unaligned */ + u8 key_length[2]; + /* does not repeat within the life of the keying material used to + * encrypt the Key field; 64-bit NTP timestamp MAY be used here */ + u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN]; + u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */ + u8 key_index; /* key flag in the most significant bit: + * 0 = broadcast (default key), + * 1 = unicast (key mapping key); key index is in the + * 7 least significant bits */ + /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as + * the key */ + u8 key_signature[IEEE8021X_KEY_SIGN_LEN]; + + /* followed by key: if packet body length = 44 + key length, then the + * key field (of key_length bytes) contains the key in encrypted form; + * if packet body length = 44, key field is absent and key_length + * represents the number of least significant octets from + * MS-MPPE-Send-Key attribute to be used as the keying material; + * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */ +} STRUCT_PACKED; + +#endif /* EAPOL_COMMON_H */ diff --git a/components/wpa_supplicant/include/wpa/hostapd.h b/components/wpa_supplicant/include/wpa/hostapd.h new file mode 100755 index 00000000..1d52659a --- /dev/null +++ b/components/wpa_supplicant/include/wpa/hostapd.h @@ -0,0 +1,312 @@ +/* + * hostapd / Initialization and configuration + * Copyright (c) 2002-2009, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef HOSTAPD_H +#define HOSTAPD_H + +#include "wpa/defs.h" +#include "wpa/ap_config.h" + +struct wpa_driver_ops; +struct wpa_ctrl_dst; +struct radius_server_data; +struct upnp_wps_device_sm; +struct hostapd_data; +struct sta_info; +struct hostap_sta_driver_data; +struct ieee80211_ht_capabilities; +struct full_dynamic_vlan; +enum wps_event; +union wps_event_data; + +struct hostapd_iface; + +struct hapd_interfaces { + int (*reload_config)(struct hostapd_iface *iface); + struct hostapd_config * (*config_read_cb)(const char *config_fname); + int (*ctrl_iface_init)(struct hostapd_data *hapd); + void (*ctrl_iface_deinit)(struct hostapd_data *hapd); + int (*for_each_interface)(struct hapd_interfaces *interfaces, + int (*cb)(struct hostapd_iface *iface, + void *ctx), void *ctx); + int (*driver_init)(struct hostapd_iface *iface); + + size_t count; + int global_ctrl_sock; + char *global_iface_path; + char *global_iface_name; + struct hostapd_iface **iface; +}; + + +struct hostapd_probereq_cb { + int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid, + const u8 *ie, size_t ie_len, int ssi_signal); + void *ctx; +}; + +#define HOSTAPD_RATE_BASIC 0x00000001 + +struct hostapd_rate_data { + int rate; /* rate in 100 kbps */ + int flags; /* HOSTAPD_RATE_ flags */ +}; + +struct hostapd_frame_info { + u32 channel; + u32 datarate; + int ssi_signal; /* dBm */ +}; + + +/** + * struct hostapd_data - hostapd per-BSS data structure + */ +struct hostapd_data { +// struct hostapd_iface *iface; + struct hostapd_config *iconf; + struct hostapd_bss_config *conf; + int interface_added; /* virtual interface added for this BSS */ + + u8 own_addr[ETH_ALEN]; + + int num_sta; /* number of entries in sta_list */ +// struct sta_info *sta_list; /* STA info list head */ +//#define STA_HASH_SIZE 256 +//#define STA_HASH(sta) (sta[5]) +// struct sta_info *sta_hash[STA_HASH_SIZE]; + +// /* +// * Bitfield for indicating which AIDs are allocated. Only AID values +// * 1-2007 are used and as such, the bit at index 0 corresponds to AID +// * 1. +// */ +//#define AID_WORDS ((2008 + 31) / 32) +// u32 sta_aid[AID_WORDS]; + +// const struct wpa_driver_ops *driver; +// void *drv_priv; + +// void (*new_assoc_sta_cb)(struct hostapd_data *hapd, +// struct sta_info *sta, int reassoc); + +// void *msg_ctx; /* ctx for wpa_msg() calls */ +// void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */ + +// struct radius_client_data *radius; +// u32 acct_session_id_hi, acct_session_id_lo; +// struct radius_das_data *radius_das; + +// struct iapp_data *iapp; + +// struct hostapd_cached_radius_acl *acl_cache; +// struct hostapd_acl_query_data *acl_queries; + + struct wpa_authenticator *wpa_auth; +// struct eapol_authenticator *eapol_auth; + +// struct rsn_preauth_interface *preauth_iface; +// time_t michael_mic_failure; +// int michael_mic_failures; +// int tkip_countermeasures; + +// int ctrl_sock; +// struct wpa_ctrl_dst *ctrl_dst; + +// void *ssl_ctx; +// void *eap_sim_db_priv; +// struct radius_server_data *radius_srv; + +// int parameter_set_count; + + /* Time Advertisement */ +// u8 time_update_counter; +// struct wpabuf *time_adv; + +#ifdef CONFIG_FULL_DYNAMIC_VLAN + struct full_dynamic_vlan *full_dynamic_vlan; +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ + +// struct l2_packet_data *l2; +// struct wps_context *wps; + +// int beacon_set_done; +// struct wpabuf *wps_beacon_ie; +// struct wpabuf *wps_probe_resp_ie; +#ifdef CONFIG_WPS + unsigned int ap_pin_failures; + unsigned int ap_pin_failures_consecutive; + struct upnp_wps_device_sm *wps_upnp; + unsigned int ap_pin_lockout_time; +#endif /* CONFIG_WPS */ + +// struct hostapd_probereq_cb *probereq_cb; +// size_t num_probereq_cb; + +// void (*public_action_cb)(void *ctx, const u8 *buf, size_t len, +// int freq); +// void *public_action_cb_ctx; + +// int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len, +// int freq); +// void *vendor_action_cb_ctx; + +// void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr, +// const u8 *uuid_e); +// void *wps_reg_success_cb_ctx; + +// void (*wps_event_cb)(void *ctx, enum wps_event event, +// union wps_event_data *data); +// void *wps_event_cb_ctx; + +// void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr, +// int authorized, const u8 *p2p_dev_addr); +// void *sta_authorized_cb_ctx; + +// void (*setup_complete_cb)(void *ctx); +// void *setup_complete_cb_ctx; + +#ifdef CONFIG_P2P + struct p2p_data *p2p; + struct p2p_group *p2p_group; + struct wpabuf *p2p_beacon_ie; + struct wpabuf *p2p_probe_resp_ie; + + /* Number of non-P2P association stations */ + int num_sta_no_p2p; + + /* Periodic NoA (used only when no non-P2P clients in the group) */ + int noa_enabled; + int noa_start; + int noa_duration; +#endif /* CONFIG_P2P */ +#ifdef CONFIG_INTERWORKING + size_t gas_frag_limit; +#endif /* CONFIG_INTERWORKING */ + +#ifdef CONFIG_SQLITE + struct hostapd_eap_user tmp_eap_user; +#endif /* CONFIG_SQLITE */ +}; + +#if 0 +/** + * struct hostapd_iface - hostapd per-interface data structure + */ +struct hostapd_iface { + struct hapd_interfaces *interfaces; + void *owner; + char *config_fname; + struct hostapd_config *conf; + + size_t num_bss; + struct hostapd_data **bss; + + int num_ap; /* number of entries in ap_list */ + struct ap_info *ap_list; /* AP info list head */ + struct ap_info *ap_hash[STA_HASH_SIZE]; + struct ap_info *ap_iter_list; + + unsigned int drv_flags; + + /* + * A bitmap of supported protocols for probe response offload. See + * struct wpa_driver_capa in driver.h + */ + unsigned int probe_resp_offloads; + + struct hostapd_hw_modes *hw_features; + int num_hw_features; + struct hostapd_hw_modes *current_mode; + /* Rates that are currently used (i.e., filtered copy of + * current_mode->channels */ + int num_rates; + struct hostapd_rate_data *current_rates; + int *basic_rates; + int freq; + + u16 hw_flags; + + /* Number of associated Non-ERP stations (i.e., stations using 802.11b + * in 802.11g BSS) */ + int num_sta_non_erp; + + /* Number of associated stations that do not support Short Slot Time */ + int num_sta_no_short_slot_time; + + /* Number of associated stations that do not support Short Preamble */ + int num_sta_no_short_preamble; + + int olbc; /* Overlapping Legacy BSS Condition */ + + /* Number of HT associated stations that do not support greenfield */ + int num_sta_ht_no_gf; + + /* Number of associated non-HT stations */ + int num_sta_no_ht; + + /* Number of HT associated stations 20 MHz */ + int num_sta_ht_20mhz; + + /* Overlapping BSS information */ + int olbc_ht; + + u16 ht_op_mode; + void (*scan_cb)(struct hostapd_iface *iface); +}; +#endif + +#if 0 +/* hostapd.c */ +int hostapd_for_each_interface(struct hapd_interfaces *interfaces, + int (*cb)(struct hostapd_iface *iface, + void *ctx), void *ctx); +int hostapd_reload_config(struct hostapd_iface *iface); +struct hostapd_data * +hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, + struct hostapd_config *conf, + struct hostapd_bss_config *bss); +int hostapd_setup_interface(struct hostapd_iface *iface); +int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); +void hostapd_interface_deinit(struct hostapd_iface *iface); +void hostapd_interface_free(struct hostapd_iface *iface); +void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, + int reassoc); +void hostapd_interface_deinit_free(struct hostapd_iface *iface); +int hostapd_enable_iface(struct hostapd_iface *hapd_iface); +int hostapd_reload_iface(struct hostapd_iface *hapd_iface); +int hostapd_disable_iface(struct hostapd_iface *hapd_iface); +int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf); +int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf); + +/* utils.c */ +int hostapd_register_probereq_cb(struct hostapd_data *hapd, + int (*cb)(void *ctx, const u8 *sa, + const u8 *da, const u8 *bssid, + const u8 *ie, size_t ie_len, + int ssi_signal), + void *ctx); +void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr); + +/* drv_callbacks.c (TODO: move to somewhere else?) */ +int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, + const u8 *ie, size_t ielen, int reassoc); +void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); +void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr); +int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, + const u8 *bssid, const u8 *ie, size_t ie_len, + int ssi_signal); +void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, + int offset); + +const struct hostapd_eap_user * +hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, + size_t identity_len, int phase2); +#endif + +#endif /* HOSTAPD_H */ diff --git a/components/wpa_supplicant/include/wpa/ieee80211_crypto.h b/components/wpa_supplicant/include/wpa/ieee80211_crypto.h new file mode 100755 index 00000000..be0fb9aa --- /dev/null +++ b/components/wpa_supplicant/include/wpa/ieee80211_crypto.h @@ -0,0 +1,226 @@ +/*- + * Copyright (c) 2001 Atsushi Onoe + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $FreeBSD$ + */ + +/* + * copyright (c) 2010-2011 Espressif System + */ +#ifndef _NET80211_IEEE80211_CRYPTO_H_ +#define _NET80211_IEEE80211_CRYPTO_H_ + +//#include "pp/esf_buf.h" + +/* + * 802.11 protocol crypto-related definitions. + */ +#define IEEE80211_KEYBUF_SIZE 16 +#define IEEE80211_MICBUF_SIZE (8+8) /* space for both tx+rx keys */ + +/* + * Old WEP-style key. Deprecated. + */ + +#if 0 +struct ieee80211_rsnparms { + uint8_t rsn_mcastcipher; /* mcast/group cipher */ + uint8_t rsn_mcastkeylen; /* mcast key length */ + uint8_t rsn_ucastcipher; /* selected unicast cipher */ + uint8_t rsn_ucastkeylen; /* unicast key length */ + uint8_t rsn_keymgmt; /* selected key mgmt algo */ + uint16_t rsn_caps; /* capabilities */ +}; +#endif //0000 + +/* + * Template for a supported cipher. Ciphers register with the + * crypto code and are typically loaded as separate modules + * (the null cipher is always present). + * XXX may need refcnts + */ + +/* + * Crypto key state. There is sufficient room for all supported + * ciphers (see below). The underlying ciphers are handled + * separately through loadable cipher modules that register with + * the generic crypto support. A key has a reference to an instance + * of the cipher; any per-key state is hung off wk_private by the + * cipher when it is attached. Ciphers are automatically called + * to detach and cleanup any such state when the key is deleted. + * + * The generic crypto support handles encap/decap of cipher-related + * frame contents for both hardware- and software-based implementations. + * A key requiring software crypto support is automatically flagged and + * the cipher is expected to honor this and do the necessary work. + * Ciphers such as TKIP may also support mixed hardware/software + * encrypt/decrypt and MIC processing. + */ +typedef uint16_t ieee80211_keyix; /* h/w key index */ + +struct ieee80211_key { + uint8_t wk_keylen; /* key length in bytes */ + uint8_t wk_pad; + uint16_t wk_flags; +#define IEEE80211_KEY_XMIT 0x0001 /* key used for xmit */ +#define IEEE80211_KEY_RECV 0x0002 /* key used for recv */ +#define IEEE80211_KEY_GROUP 0x0004 /* key used for WPA group operation */ +#define IEEE80211_KEY_SWENCRYPT 0x0010 /* host-based encrypt */ +#define IEEE80211_KEY_SWDECRYPT 0x0020 /* host-based decrypt */ +#define IEEE80211_KEY_SWENMIC 0x0040 /* host-based enmic */ +#define IEEE80211_KEY_SWDEMIC 0x0080 /* host-based demic */ +#define IEEE80211_KEY_DEVKEY 0x0100 /* device key request completed */ +#define IEEE80211_KEY_CIPHER0 0x1000 /* cipher-specific action 0 */ +#define IEEE80211_KEY_CIPHER1 0x2000 /* cipher-specific action 1 */ +#define IEEE80211_KEY_EMPTY 0x0000 + ieee80211_keyix wk_keyix; /* h/w key index */ + ieee80211_keyix wk_rxkeyix; /* optional h/w rx key index */ + uint8_t wk_key[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE]; +#define wk_txmic wk_key+IEEE80211_KEYBUF_SIZE+0 /* XXX can't () right */ +#define wk_rxmic wk_key+IEEE80211_KEYBUF_SIZE+8 /* XXX can't () right */ + /* key receive sequence counter */ + uint64_t wk_keyrsc[IEEE80211_TID_SIZE]; + uint64_t wk_keytsc; /* key transmit sequence counter */ + const struct ieee80211_cipher *wk_cipher; + //void *wk_private; /* private cipher state */ + //uint8_t wk_macaddr[IEEE80211_ADDR_LEN]; //JLU: no need ... +}; +#define IEEE80211_KEY_COMMON /* common flags passed in by apps */\ + (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV | IEEE80211_KEY_GROUP) +#define IEEE80211_KEY_DEVICE /* flags owned by device driver */\ + (IEEE80211_KEY_DEVKEY|IEEE80211_KEY_CIPHER0|IEEE80211_KEY_CIPHER1) + +#define IEEE80211_KEY_SWCRYPT \ + (IEEE80211_KEY_SWENCRYPT | IEEE80211_KEY_SWDECRYPT) +#define IEEE80211_KEY_SWMIC (IEEE80211_KEY_SWENMIC | IEEE80211_KEY_SWDEMIC) + +//#define IEEE80211_KEYIX_NONE ((ieee80211_keyix) -1) + +/* + * NB: these values are ordered carefully; there are lots of + * of implications in any reordering. Beware that 4 is used + * only to indicate h/w TKIP MIC support in driver capabilities; + * there is no separate cipher support (it's rolled into the + * TKIP cipher support). + */ +#define IEEE80211_CIPHER_NONE 0 /* pseudo value */ +#define IEEE80211_CIPHER_TKIP 1 +#define IEEE80211_CIPHER_AES_OCB 2 +#define IEEE80211_CIPHER_AES_CCM 3 +#define IEEE80211_CIPHER_TKIPMIC 4 /* TKIP MIC capability */ +#define IEEE80211_CIPHER_CKIP 5 +#define IEEE80211_CIPHER_WEP 6 +#define IEEE80211_CIPHER_WEP40 7 +#define IEEE80211_CIPHER_WEP104 8 + + +#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+2) + +/* capability bits in ic_cryptocaps/iv_cryptocaps */ +#define IEEE80211_CRYPTO_NONE (1<wk_cipher == &ieee80211_cipher_none) + +struct ieee80211_key *ieee80211_crypto_encap(struct ieee80211_conn *, + esf_buf *); + +struct ieee80211_key *ieee80211_crypto_decap(struct ieee80211_conn *, + esf_buf *, int); + +#if 0 //H/W MIC +/* + * Check and remove any MIC. + */ +static INLINE int +ieee80211_crypto_demic(struct ieee80211vap *vap, struct ieee80211_key *k, + esf_buf *m, int force) +{ + const struct ieee80211_cipher *cip = k->wk_cipher; + return (cip->ic_miclen > 0 ? cip->ic_demic(k, m, force) : 1); +} + +/* + * Add any MIC. + */ +static INLINE int +ieee80211_crypto_enmic(struct ieee80211vap *vap, + struct ieee80211_key *k, esf_buf *m, int force) +{ + const struct ieee80211_cipher *cip = k->wk_cipher; + return (cip->ic_miclen > 0 ? cip->ic_enmic(k, m, force) : 1); +} +#endif //0000 + +/* + * Setup crypto support for a device/shared instance. + */ +void ieee80211_crypto_attach(struct ieee80211com *ic); + +/* + * Reset key state to an unused state. The crypto + * key allocation mechanism insures other state (e.g. + * key data) is properly setup before a key is used. + */ +static inline void +ieee80211_crypto_resetkey(struct ieee80211_key *k) +{ + k->wk_cipher = NULL; + k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; +} + +/* + * Crypt-related notification methods. + */ +//void ieee80211_notify_replay_failure(const struct ieee80211_frame *, const struct ieee80211_key *, +// uint64_t rsc, int tid); +//void ieee80211_notify_michael_failure(const struct ieee80211_frame *, u_int keyix); + +#endif /* _NET80211_IEEE80211_CRYPTO_H_ */ diff --git a/components/wpa_supplicant/include/wpa/ieee802_11_defs.h b/components/wpa_supplicant/include/wpa/ieee802_11_defs.h new file mode 100755 index 00000000..4881e39a --- /dev/null +++ b/components/wpa_supplicant/include/wpa/ieee802_11_defs.h @@ -0,0 +1,607 @@ +/* + * IEEE 802.11 Frame type definitions + * Copyright (c) 2002-2009, Jouni Malinen + * Copyright (c) 2007-2008 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef IEEE802_11_DEFS_H +#define IEEE802_11_DEFS_H + +/* IEEE 802.11 defines */ + +#define WLAN_FC_PVER 0x0003 +#define WLAN_FC_TODS 0x0100 +#define WLAN_FC_FROMDS 0x0200 +#define WLAN_FC_MOREFRAG 0x0400 +#define WLAN_FC_RETRY 0x0800 +#define WLAN_FC_PWRMGT 0x1000 +#define WLAN_FC_MOREDATA 0x2000 +#define WLAN_FC_ISWEP 0x4000 +#define WLAN_FC_ORDER 0x8000 + +#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2) +#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4) + +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0))) +#define WLAN_GET_SEQ_SEQ(seq) \ + (((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4) + +#define WLAN_FC_TYPE_MGMT 0 +#define WLAN_FC_TYPE_CTRL 1 +#define WLAN_FC_TYPE_DATA 2 + +/* management */ +#define WLAN_FC_STYPE_ASSOC_REQ 0 +#define WLAN_FC_STYPE_ASSOC_RESP 1 +#define WLAN_FC_STYPE_REASSOC_REQ 2 +#define WLAN_FC_STYPE_REASSOC_RESP 3 +#define WLAN_FC_STYPE_PROBE_REQ 4 +#define WLAN_FC_STYPE_PROBE_RESP 5 +#define WLAN_FC_STYPE_BEACON 8 +#define WLAN_FC_STYPE_ATIM 9 +#define WLAN_FC_STYPE_DISASSOC 10 +#define WLAN_FC_STYPE_AUTH 11 +#define WLAN_FC_STYPE_DEAUTH 12 +#define WLAN_FC_STYPE_ACTION 13 + +/* control */ +#define WLAN_FC_STYPE_PSPOLL 10 +#define WLAN_FC_STYPE_RTS 11 +#define WLAN_FC_STYPE_CTS 12 +#define WLAN_FC_STYPE_ACK 13 +#define WLAN_FC_STYPE_CFEND 14 +#define WLAN_FC_STYPE_CFENDACK 15 + +/* data */ +#define WLAN_FC_STYPE_DATA 0 +#define WLAN_FC_STYPE_DATA_CFACK 1 +#define WLAN_FC_STYPE_DATA_CFPOLL 2 +#define WLAN_FC_STYPE_DATA_CFACKPOLL 3 +#define WLAN_FC_STYPE_NULLFUNC 4 +#define WLAN_FC_STYPE_CFACK 5 +#define WLAN_FC_STYPE_CFPOLL 6 +#define WLAN_FC_STYPE_CFACKPOLL 7 +#define WLAN_FC_STYPE_QOS_DATA 8 + +/* Authentication algorithms */ +#define WLAN_AUTH_OPEN 0 +#define WLAN_AUTH_SHARED_KEY 1 +#define WLAN_AUTH_FT 2 +#define WLAN_AUTH_LEAP 128 + +#define WLAN_AUTH_CHALLENGE_LEN 128 + +#define WLAN_CAPABILITY_ESS BIT(0) +#define WLAN_CAPABILITY_IBSS BIT(1) +#define WLAN_CAPABILITY_CF_POLLABLE BIT(2) +#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3) +#define WLAN_CAPABILITY_PRIVACY BIT(4) +#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5) +#define WLAN_CAPABILITY_PBCC BIT(6) +#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7) +#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8) +#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10) +#define WLAN_CAPABILITY_DSSS_OFDM BIT(13) + +/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */ +#define WLAN_STATUS_SUCCESS 0 +#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 +#define WLAN_STATUS_CAPS_UNSUPPORTED 10 +#define WLAN_STATUS_REASSOC_NO_ASSOC 11 +#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 +#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 +#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 +#define WLAN_STATUS_CHALLENGE_FAIL 15 +#define WLAN_STATUS_AUTH_TIMEOUT 16 +#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 +#define WLAN_STATUS_ASSOC_DENIED_RATES 18 +/* IEEE 802.11b */ +#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 +#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 +#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 +/* IEEE 802.11h */ +#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22 +#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23 +#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 +/* IEEE 802.11g */ +#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 +#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26 +#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27 +#define WLAN_STATUS_R0KH_UNREACHABLE 28 +/* IEEE 802.11w */ +#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30 +#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 +#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32 +#define WLAN_STATUS_REQUEST_DECLINED 37 +#define WLAN_STATUS_INVALID_PARAMETERS 38 +/* IEEE 802.11i */ +#define WLAN_STATUS_INVALID_IE 40 +#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 +#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 +#define WLAN_STATUS_AKMP_NOT_VALID 43 +#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 +#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45 +#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46 +#define WLAN_STATUS_TS_NOT_CREATED 47 +#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48 +#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49 +#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50 +#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51 +/* IEEE 802.11r */ +#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 +#define WLAN_STATUS_INVALID_PMKID 53 +#define WLAN_STATUS_INVALID_MDIE 54 +#define WLAN_STATUS_INVALID_FTIE 55 + +/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ +#define WLAN_REASON_UNSPECIFIED 1 +#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 +#define WLAN_REASON_DEAUTH_LEAVING 3 +#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 +#define WLAN_REASON_DISASSOC_AP_BUSY 5 +#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 +#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 +#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 +#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 +/* IEEE 802.11h */ +#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10 +#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 +/* IEEE 802.11i */ +#define WLAN_REASON_INVALID_IE 13 +#define WLAN_REASON_MICHAEL_MIC_FAILURE 14 +#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15 +#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 +#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17 +#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18 +#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19 +#define WLAN_REASON_AKMP_NOT_VALID 20 +#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21 +#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22 +#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23 +#define WLAN_REASON_CIPHER_SUITE_REJECTED 24 + + +/* Information Element IDs */ +#define WLAN_EID_SSID 0 +#define WLAN_EID_SUPP_RATES 1 +#define WLAN_EID_FH_PARAMS 2 +#define WLAN_EID_DS_PARAMS 3 +#define WLAN_EID_CF_PARAMS 4 +#define WLAN_EID_TIM 5 +#define WLAN_EID_IBSS_PARAMS 6 +#define WLAN_EID_COUNTRY 7 +#define WLAN_EID_CHALLENGE 16 +/* EIDs defined by IEEE 802.11h - START */ +#define WLAN_EID_PWR_CONSTRAINT 32 +#define WLAN_EID_PWR_CAPABILITY 33 +#define WLAN_EID_TPC_REQUEST 34 +#define WLAN_EID_TPC_REPORT 35 +#define WLAN_EID_SUPPORTED_CHANNELS 36 +#define WLAN_EID_CHANNEL_SWITCH 37 +#define WLAN_EID_MEASURE_REQUEST 38 +#define WLAN_EID_MEASURE_REPORT 39 +#define WLAN_EID_QUITE 40 +#define WLAN_EID_IBSS_DFS 41 +/* EIDs defined by IEEE 802.11h - END */ +#define WLAN_EID_ERP_INFO 42 +#define WLAN_EID_HT_CAP 45 +#define WLAN_EID_RSN 48 +#define WLAN_EID_EXT_SUPP_RATES 50 +#define WLAN_EID_MOBILITY_DOMAIN 54 +#define WLAN_EID_FAST_BSS_TRANSITION 55 +#define WLAN_EID_TIMEOUT_INTERVAL 56 +#define WLAN_EID_RIC_DATA 57 +#define WLAN_EID_HT_OPERATION 61 +#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 +#define WLAN_EID_20_40_BSS_COEXISTENCE 72 +#define WLAN_EID_20_40_BSS_INTOLERANT 73 +#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 +#define WLAN_EID_MMIE 76 +#define WLAN_EID_VENDOR_SPECIFIC 221 + + +/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ +#define WLAN_ACTION_SPECTRUM_MGMT 0 +#define WLAN_ACTION_QOS 1 +#define WLAN_ACTION_DLS 2 +#define WLAN_ACTION_BLOCK_ACK 3 +#define WLAN_ACTION_PUBLIC 4 +#define WLAN_ACTION_RADIO_MEASUREMENT 5 +#define WLAN_ACTION_FT 6 +#define WLAN_ACTION_HT 7 +#define WLAN_ACTION_SA_QUERY 8 +#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */ + +/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ +#define WLAN_SA_QUERY_REQUEST 0 +#define WLAN_SA_QUERY_RESPONSE 1 + +#define WLAN_SA_QUERY_TR_ID_LEN 2 + +/* Timeout Interval Type */ +#define WLAN_TIMEOUT_REASSOC_DEADLINE 1 +#define WLAN_TIMEOUT_KEY_LIFETIME 2 +#define WLAN_TIMEOUT_ASSOC_COMEBACK 3 + + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct ieee80211_hdr { + le16 frame_control; + le16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + le16 seq_ctrl; + /* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame + */ +} STRUCT_PACKED; + +#define IEEE80211_DA_FROMDS addr1 +#define IEEE80211_BSSID_FROMDS addr2 +#define IEEE80211_SA_FROMDS addr3 + +#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr)) + +#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) + +struct ieee80211_mgmt { + le16 frame_control; + le16 duration; + u8 da[6]; + u8 sa[6]; + u8 bssid[6]; + le16 seq_ctrl; + union { + struct { + le16 auth_alg; + le16 auth_transaction; + le16 status_code; + /* possibly followed by Challenge text */ + u8 variable[0]; + } STRUCT_PACKED auth; + struct { + le16 reason_code; + } STRUCT_PACKED deauth; + struct { + le16 capab_info; + le16 listen_interval; + /* followed by SSID and Supported rates */ + u8 variable[0]; + } STRUCT_PACKED assoc_req; + struct { + le16 capab_info; + le16 status_code; + le16 aid; + /* followed by Supported rates */ + u8 variable[0]; + } STRUCT_PACKED assoc_resp, reassoc_resp; + struct { + le16 capab_info; + le16 listen_interval; + u8 current_ap[6]; + /* followed by SSID and Supported rates */ + u8 variable[0]; + } STRUCT_PACKED reassoc_req; + struct { + le16 reason_code; + } STRUCT_PACKED disassoc; + struct { + u8 timestamp[8]; + le16 beacon_int; + le16 capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params, TIM */ + u8 variable[0]; + } STRUCT_PACKED beacon; + struct { + /* only variable items: SSID, Supported rates */ + u8 variable[0]; + } STRUCT_PACKED probe_req; + struct { + u8 timestamp[8]; + le16 beacon_int; + le16 capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params */ + u8 variable[0]; + } STRUCT_PACKED probe_resp; + struct { + u8 category; + union { + struct { + u8 action_code; + u8 dialog_token; + u8 status_code; + u8 variable[0]; + } STRUCT_PACKED wmm_action; + struct{ + u8 action_code; + u8 element_id; + u8 length; + u8 switch_mode; + u8 new_chan; + u8 switch_count; + } STRUCT_PACKED chan_switch; + struct { + u8 action; + u8 sta_addr[ETH_ALEN]; + u8 target_ap_addr[ETH_ALEN]; + u8 variable[0]; /* FT Request */ + } STRUCT_PACKED ft_action_req; + struct { + u8 action; + u8 sta_addr[ETH_ALEN]; + u8 target_ap_addr[ETH_ALEN]; + le16 status_code; + u8 variable[0]; /* FT Request */ + } STRUCT_PACKED ft_action_resp; + struct { + u8 action; + u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; + } STRUCT_PACKED sa_query_req; + struct { + u8 action; /* */ + u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; + } STRUCT_PACKED sa_query_resp; + } u; + } STRUCT_PACKED action; + } u; +} STRUCT_PACKED; + + +struct ieee80211_ht_capabilities { + le16 ht_capabilities_info; + u8 a_mpdu_params; + u8 supported_mcs_set[16]; + le16 ht_extended_capabilities; + le32 tx_bf_capability_info; + u8 asel_capabilities; +} STRUCT_PACKED; + + +struct ieee80211_ht_operation { + u8 control_chan; + u8 ht_param; + le16 operation_mode; + le16 stbc_param; + u8 basic_set[16]; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +#define ERP_INFO_NON_ERP_PRESENT BIT(0) +#define ERP_INFO_USE_PROTECTION BIT(1) +#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) + + +#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) +#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) +#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) +#define HT_CAP_INFO_SMPS_STATIC ((u16) 0) +#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2)) +#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3))) +#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4)) +#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5)) +#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6)) +#define HT_CAP_INFO_TX_STBC ((u16) BIT(7)) +#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9))) +#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8)) +#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9)) +#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9))) +#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10)) +#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11)) +#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12)) +#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13)) +#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14)) +#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) + + +#define EXT_HT_CAP_INFO_PCO ((u16) BIT(0)) +#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1 +#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8 +#define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10)) +#define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11)) + + +#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0)) +#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1)) +#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2)) +#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3)) +#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4)) +#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5)) +#define TX_BEAMFORM_CAP_CALIB_OFFSET 6 +#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8)) +#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9)) +#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10)) +#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11 +#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13 +#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15 +#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17 +#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19 +#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21 +#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23 +#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25 + + +#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0)) +#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1)) +#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2)) +#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3)) +#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4)) +#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5)) +#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6)) + +#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) +#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) +#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) +#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2)) +#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3)) +#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) +#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) + + +#define OP_MODE_PURE 0 +#define OP_MODE_MAY_BE_LEGACY_STAS 1 +#define OP_MODE_20MHZ_HT_STA_ASSOCED 2 +#define OP_MODE_MIXED 3 + +#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ + ((le16) (0x0001 | 0x0002)) +#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 +#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2)) +#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3)) +#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4)) + +#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6)) +#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7)) +#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8)) +#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9)) +#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10)) +#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) + + +#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) + * 00:50:F2 */ +#define WPA_IE_VENDOR_TYPE 0x0050f201 +#define WPS_IE_VENDOR_TYPE 0x0050f204 + +#define WMM_OUI_TYPE 2 +#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 +#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1 +#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2 +#define WMM_VERSION 1 + +#define WMM_ACTION_CODE_ADDTS_REQ 0 +#define WMM_ACTION_CODE_ADDTS_RESP 1 +#define WMM_ACTION_CODE_DELTS 2 + +#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0 +#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1 +/* 2 - Reserved */ +#define WMM_ADDTS_STATUS_REFUSED 3 +/* 4-255 - Reserved */ + +/* WMM TSPEC Direction Field Values */ +#define WMM_TSPEC_DIRECTION_UPLINK 0 +#define WMM_TSPEC_DIRECTION_DOWNLINK 1 +/* 2 - Reserved */ +#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3 + +/* + * WMM Information Element (used in (Re)Association Request frames; may also be + * used in Beacon frames) + */ +struct wmm_information_element { + /* Element ID: 221 (0xdd); Length: 7 */ + /* required fields for WMM version 1 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 0 */ + u8 version; /* 1 for WMM version 1.0 */ + u8 qos_info; /* AP/STA specific QoS info */ + +} STRUCT_PACKED; + +#define WMM_AC_AIFSN_MASK 0x0f +#define WMM_AC_AIFNS_SHIFT 0 +#define WMM_AC_ACM 0x10 +#define WMM_AC_ACI_MASK 0x60 +#define WMM_AC_ACI_SHIFT 5 + +#define WMM_AC_ECWMIN_MASK 0x0f +#define WMM_AC_ECWMIN_SHIFT 0 +#define WMM_AC_ECWMAX_MASK 0xf0 +#define WMM_AC_ECWMAX_SHIFT 4 + +struct wmm_ac_parameter { + u8 aci_aifsn; /* AIFSN, ACM, ACI */ + u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ + le16 txop_limit; +} STRUCT_PACKED; + +/* + * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association + * Response frmaes) + */ +struct wmm_parameter_element { + /* Element ID: 221 (0xdd); Length: 24 */ + /* required fields for WMM version 1 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 1 */ + u8 version; /* 1 for WMM version 1.0 */ + u8 qos_info; /* AP/STA specif QoS info */ + u8 reserved; /* 0 */ + struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */ + +} STRUCT_PACKED; + +/* WMM TSPEC Element */ +struct wmm_tspec_element { + u8 eid; /* 221 = 0xdd */ + u8 length; /* 6 + 55 = 61 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 2 */ + u8 version; /* 1 */ + /* WMM TSPEC body (55 octets): */ + u8 ts_info[3]; + le16 nominal_msdu_size; + le16 maximum_msdu_size; + le32 minimum_service_interval; + le32 maximum_service_interval; + le32 inactivity_interval; + le32 suspension_interval; + le32 service_start_time; + le32 minimum_data_rate; + le32 mean_data_rate; + le32 peak_data_rate; + le32 maximum_burst_size; + le32 delay_bound; + le32 minimum_phy_rate; + le16 surplus_bandwidth_allowance; + le16 medium_time; +} STRUCT_PACKED; + + +/* Access Categories / ACI to AC coding */ +enum { + WMM_AC_BE = 0 /* Best Effort */, + WMM_AC_BK = 1 /* Background */, + WMM_AC_VI = 2 /* Video */, + WMM_AC_VO = 3 /* Voice */ +}; + + +#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ + +#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ + +/* cipher suite selectors */ +#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 +#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 +#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 +/* reserved: 0x000FAC03 */ +#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 +#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 +#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 + +/* AKM suite selectors */ +#define WLAN_AKM_SUITE_8021X 0x000FAC01 +#define WLAN_AKM_SUITE_PSK 0x000FAC02 + +#endif /* IEEE802_11_DEFS_H */ diff --git a/components/wpa_supplicant/include/wpa/ieee802_1x.h b/components/wpa_supplicant/include/wpa/ieee802_1x.h new file mode 100755 index 00000000..e10ff7b3 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/ieee802_1x.h @@ -0,0 +1,64 @@ +/* + * hostapd / IEEE 802.1X-2004 Authenticator + * Copyright (c) 2002-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef IEEE802_1X_H +#define IEEE802_1X_H + +struct hostapd_data; +struct sta_info; +struct eapol_state_machine; +struct hostapd_config; +struct hostapd_bss_config; +struct hostapd_radius_attr; +struct radius_msg; + + +void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, + size_t len); + +#if 0 +void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta); +void ieee802_1x_free_station(struct sta_info *sta); + +void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta); +void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta); +void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, + struct sta_info *sta, int authorized); +void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta); +int ieee802_1x_init(struct hostapd_data *hapd); +void ieee802_1x_deinit(struct hostapd_data *hapd); +int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *buf, size_t len, int ack); +int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *data, int len, int ack); +u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len); +u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, + int idx); +struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm); +const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len); +void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, + int enabled); +void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, + int valid); +void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth); +int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen); +int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, + char *buf, size_t buflen); +void hostapd_get_ntp_timestamp(u8 *buf); +char *eap_type_text(u8 type); + +const char *radius_mode_txt(struct hostapd_data *hapd); +int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta); + +int add_common_radius_attr(struct hostapd_data *hapd, + struct hostapd_radius_attr *req_attr, + struct sta_info *sta, + struct radius_msg *msg); +#endif + +#endif /* IEEE802_1X_H */ diff --git a/components/wpa_supplicant/include/wpa/includes.h b/components/wpa_supplicant/include/wpa/includes.h new file mode 100755 index 00000000..993bc499 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/includes.h @@ -0,0 +1,31 @@ +/* + * wpa_supplicant/hostapd - Default include files + * Copyright (c) 2005-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This header file is included into all C files so that commonly used header + * files can be selected with OS specific ifdef blocks in one place instead of + * having to have OS/C library specific selection in many files. + */ + +#ifndef INCLUDES_H +#define INCLUDES_H + +/* Include possible build time configuration before including anything else */ +//#include "build_config.h" //don't need anymore + +//#include +//#include +//#include +//#include +//#include + +#endif /* INCLUDES_H */ diff --git a/components/wpa_supplicant/include/wpa/list.h b/components/wpa_supplicant/include/wpa/list.h new file mode 100755 index 00000000..c8dccee8 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/list.h @@ -0,0 +1,101 @@ +/* + * Doubly-linked list + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef LIST_H +#define LIST_H + +/** + * struct dl_list - Doubly-linked list + */ +struct dl_list { + struct dl_list *next; + struct dl_list *prev; +}; + +static inline void dl_list_init(struct dl_list *list) +{ + list->next = list; + list->prev = list; +} + +static inline void dl_list_add(struct dl_list *list, struct dl_list *item) +{ + item->next = list->next; + item->prev = list; + list->next->prev = item; + list->next = item; +} + +static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item) +{ + dl_list_add(list->prev, item); +} + +static inline void dl_list_del(struct dl_list *item) +{ + item->next->prev = item->prev; + item->prev->next = item->next; + item->next = NULL; + item->prev = NULL; +} + +static inline int dl_list_empty(struct dl_list *list) +{ + return list->next == list; +} + +static inline unsigned int dl_list_len(struct dl_list *list) +{ + struct dl_list *item; + int count = 0; + for (item = list->next; item != list; item = item->next) + count++; + return count; +} + +#ifndef offsetof +#define offsetof(type, member) ((long) &((type *) 0)->member) +#endif + +#define dl_list_entry(item, type, member) \ + ((type *) ((char *) item - offsetof(type, member))) + +#define dl_list_first(list, type, member) \ + (dl_list_empty((list)) ? NULL : \ + dl_list_entry((list)->next, type, member)) + +#define dl_list_last(list, type, member) \ + (dl_list_empty((list)) ? NULL : \ + dl_list_entry((list)->prev, type, member)) + +#define dl_list_for_each(item, list, type, member) \ + for (item = dl_list_entry((list)->next, type, member); \ + &item->member != (list); \ + item = dl_list_entry(item->member.next, type, member)) + +#define dl_list_for_each_safe(item, n, list, type, member) \ + for (item = dl_list_entry((list)->next, type, member), \ + n = dl_list_entry(item->member.next, type, member); \ + &item->member != (list); \ + item = n, n = dl_list_entry(n->member.next, type, member)) + +#define dl_list_for_each_reverse(item, list, type, member) \ + for (item = dl_list_entry((list)->prev, type, member); \ + &item->member != (list); \ + item = dl_list_entry(item->member.prev, type, member)) + +#define DEFINE_DL_LIST(name) \ + struct dl_list name = { &(name), &(name) } + +#endif /* LIST_H */ diff --git a/components/wpa_supplicant/include/wpa/sta_info.h b/components/wpa_supplicant/include/wpa/sta_info.h new file mode 100755 index 00000000..44874a2f --- /dev/null +++ b/components/wpa_supplicant/include/wpa/sta_info.h @@ -0,0 +1,194 @@ +/* + * hostapd / Station table + * Copyright (c) 2002-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef STA_INFO_H +#define STA_INFO_H + +/* STA flags */ +#define WLAN_STA_AUTH BIT(0) +#define WLAN_STA_ASSOC BIT(1) +#define WLAN_STA_PS BIT(2) +#define WLAN_STA_TIM BIT(3) +#define WLAN_STA_PERM BIT(4) +#define WLAN_STA_AUTHORIZED BIT(5) +#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ +#define WLAN_STA_SHORT_PREAMBLE BIT(7) +#define WLAN_STA_PREAUTH BIT(8) +#define WLAN_STA_WMM BIT(9) +#define WLAN_STA_MFP BIT(10) +#define WLAN_STA_HT BIT(11) +#define WLAN_STA_WPS BIT(12) +#define WLAN_STA_MAYBE_WPS BIT(13) +#define WLAN_STA_WDS BIT(14) +#define WLAN_STA_ASSOC_REQ_OK BIT(15) +#define WLAN_STA_WPS2 BIT(16) +#define WLAN_STA_GAS BIT(17) +#define WLAN_STA_VHT BIT(18) +#define WLAN_STA_PENDING_DISASSOC_CB BIT(29) +#define WLAN_STA_PENDING_DEAUTH_CB BIT(30) +#define WLAN_STA_NONERP BIT(31) + +/* Maximum number of supported rates (from both Supported Rates and Extended + * Supported Rates IEs). */ +#define WLAN_SUPP_RATES_MAX 32 + + +struct sta_info { + struct sta_info *next; /* next entry in sta list */ + struct sta_info *hnext; /* next entry in hash table list */ + u8 addr[6]; + u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ + u32 flags; /* Bitfield of WLAN_STA_* */ + u16 capability; + u16 listen_interval; /* or beacon_int for APs */ + u8 supported_rates[WLAN_SUPP_RATES_MAX]; + int supported_rates_len; +// u8 qosinfo; /* Valid when WLAN_STA_WMM is set */ + +// unsigned int nonerp_set:1; +// unsigned int no_short_slot_time_set:1; +// unsigned int no_short_preamble_set:1; +// unsigned int no_ht_gf_set:1; +// unsigned int no_ht_set:1; +// unsigned int ht_20mhz_set:1; +// unsigned int no_p2p_set:1; + + u16 auth_alg; +// u8 previous_ap[6]; + + enum { + STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE + } timeout_next; + +// u16 deauth_reason; +// u16 disassoc_reason; + + /* IEEE 802.1X related data */ +// struct eapol_state_machine *eapol_sm; + + /* IEEE 802.11f (IAPP) related data */ +// struct ieee80211_mgmt *last_assoc_req; + +// u32 acct_session_id_hi; +// u32 acct_session_id_lo; +// time_t acct_session_start; +// int acct_session_started; +// int acct_terminate_cause; /* Acct-Terminate-Cause */ +// int acct_interim_interval; /* Acct-Interim-Interval */ + +// unsigned long last_rx_bytes; +// unsigned long last_tx_bytes; +// u32 acct_input_gigawords; /* Acct-Input-Gigawords */ +// u32 acct_output_gigawords; /* Acct-Output-Gigawords */ + +// u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */ + + struct wpa_state_machine *wpa_sm; +// struct rsn_preauth_interface *preauth_iface; + + struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */ +// struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */ + +// int vlan_id; + /* PSKs from RADIUS authentication server */ +// struct hostapd_sta_wpa_psk_short *psk; + +// char *identity; /* User-Name from RADIUS */ +// char *radius_cui; /* Chargeable-User-Identity from RADIUS */ + +// struct ieee80211_ht_capabilities *ht_capabilities; +// struct ieee80211_vht_capabilities *vht_capabilities; + +#ifdef CONFIG_IEEE80211W + 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_time sa_query_start; +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_INTERWORKING +#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */ + struct gas_dialog_info *gas_dialog; + u8 gas_dialog_next; +#endif /* CONFIG_INTERWORKING */ + +// struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */ +// struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */ +// struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */ + +// struct os_time connected_time; + +#ifdef CONFIG_SAE + enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state; + u16 sae_send_confirm; +#endif /* CONFIG_SAE */ +}; + + +/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has + * passed since last received frame from the station, a nullfunc data frame is + * sent to the station. If this frame is not acknowledged and no other frames + * have been received, the station will be disassociated after + * AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated + * after AP_DEAUTH_DELAY seconds has passed after disassociation. */ +#define AP_MAX_INACTIVITY (5 * 60) +#define AP_DISASSOC_DELAY (1) +#define AP_DEAUTH_DELAY (1) +/* Number of seconds to keep STA entry with Authenticated flag after it has + * been disassociated. */ +#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30) +/* Number of seconds to keep STA entry after it has been deauthenticated. */ +#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5) + + +struct hostapd_data; + +int ap_for_each_sta(struct hostapd_data *hapd, + int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, + void *ctx), + void *ctx); +struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta); +void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta); +void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta); +void hostapd_free_stas(struct hostapd_data *hapd); +void ap_handle_timer(void *eloop_ctx, void *timeout_ctx); +void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, + u32 session_timeout); +void ap_sta_no_session_timeout(struct hostapd_data *hapd, + struct sta_info *sta); +struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr); +void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, + u16 reason); +void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, + u16 reason); +#ifdef CONFIG_WPS +int ap_sta_wps_cancel(struct hostapd_data *hapd, + struct sta_info *sta, void *ctx); +#endif /* CONFIG_WPS */ +int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, + int old_vlanid); +void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta); +void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta); +int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta); +void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *addr, u16 reason); + +void ap_sta_set_authorized(struct hostapd_data *hapd, + struct sta_info *sta, int authorized); +static inline int ap_sta_is_authorized(struct sta_info *sta) +{ + return sta->flags & WLAN_STA_AUTHORIZED; +} + +void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta); +void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta); + +#endif /* STA_INFO_H */ diff --git a/components/wpa_supplicant/include/wpa/state_machine.h b/components/wpa_supplicant/include/wpa/state_machine.h new file mode 100755 index 00000000..ce8c51e7 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/state_machine.h @@ -0,0 +1,138 @@ +/* + * wpa_supplicant/hostapd - State machine definitions + * Copyright (c) 2002-2005, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + * + * This file includes a set of pre-processor macros that can be used to + * implement a state machine. In addition to including this header file, each + * file implementing a state machine must define STATE_MACHINE_DATA to be the + * data structure including state variables (enum machine_state, + * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used + * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define + * a group of state machines with shared data structure, STATE_MACHINE_ADDR + * needs to be defined to point to the MAC address used in debug output. + * SM_ENTRY_M macro can be used to define similar group of state machines + * without this additional debug info. + */ + +#ifndef STATE_MACHINE_H +#define STATE_MACHINE_H + +/** + * SM_STATE - Declaration of a state machine function + * @machine: State machine name + * @state: State machine state + * + * This macro is used to declare a state machine function. It is used in place + * of a C function definition to declare functions to be run when the state is + * entered by calling SM_ENTER or SM_ENTER_GLOBAL. + */ +#define SM_STATE(machine, state) \ +static void ICACHE_FLASH_ATTR sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \ + int global) + +/** + * SM_ENTRY - State machine function entry point + * @machine: State machine name + * @state: State machine state + * + * This macro is used inside each state machine function declared with + * SM_STATE. SM_ENTRY should be in the beginning of the function body, but + * after declaration of possible local variables. This macro prints debug + * information about state transition and update the state machine state. + */ +#define SM_ENTRY(machine, state) \ +if (!global || sm->machine ## _state != machine ## _ ## state) { \ + sm->changed = TRUE; \ + wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \ + " entering state " #state); \ +} \ +sm->machine ## _state = machine ## _ ## state; + +/** + * SM_ENTRY_M - State machine function entry point for state machine group + * @machine: State machine name + * @_state: State machine state + * @data: State variable prefix (full variable: prefix_state) + * + * This macro is like SM_ENTRY, but for state machine groups that use a shared + * data structure for more than one state machine. Both machine and prefix + * parameters are set to "sub-state machine" name. prefix is used to allow more + * than one state variable to be stored in the same data structure. + */ +#define SM_ENTRY_M(machine, _state, data) \ +if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \ + sm->changed = TRUE; \ + wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \ + #machine " entering state " #_state); \ +} \ +sm->data ## _ ## state = machine ## _ ## _state; + +/** + * SM_ENTRY_MA - State machine function entry point for state machine group + * @machine: State machine name + * @_state: State machine state + * @data: State variable prefix (full variable: prefix_state) + * + * This macro is like SM_ENTRY_M, but a MAC address is included in debug + * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to + * be included in debug. + */ +#define SM_ENTRY_MA(machine, _state, data) \ +if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \ + sm->changed = TRUE; \ + wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \ + #machine " entering state " #_state"\n", \ + MAC2STR(STATE_MACHINE_ADDR)); \ +} \ +sm->data ## _ ## state = machine ## _ ## _state; + +/** + * SM_ENTER - Enter a new state machine state + * @machine: State machine name + * @state: State machine state + * + * This macro expands to a function call to a state machine function defined + * with SM_STATE macro. SM_ENTER is used in a state machine step function to + * move the state machine to a new state. + */ +#define SM_ENTER(machine, state) \ +sm_ ## machine ## _ ## state ## _Enter(sm, 0) + +/** + * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule + * @machine: State machine name + * @state: State machine state + * + * This macro is like SM_ENTER, but this is used when entering a new state + * based on a global (not specific to any particular state) rule. A separate + * macro is used to avoid unwanted debug message floods when the same global + * rule is forcing a state machine to remain in on state. + */ +#define SM_ENTER_GLOBAL(machine, state) \ +sm_ ## machine ## _ ## state ## _Enter(sm, 1) + +/** + * SM_STEP - Declaration of a state machine step function + * @machine: State machine name + * + * This macro is used to declare a state machine step function. It is used in + * place of a C function definition to declare a function that is used to move + * state machine to a new state based on state variables. This function uses + * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state. + */ +#define SM_STEP(machine) \ +static void ICACHE_FLASH_ATTR sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm) + +/** + * SM_STEP_RUN - Call the state machine step function + * @machine: State machine name + * + * This macro expands to a function call to a state machine step function + * defined with SM_STEP macro. + */ +#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm) + +#endif /* STATE_MACHINE_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa.h b/components/wpa_supplicant/include/wpa/wpa.h new file mode 100755 index 00000000..8a39d376 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa.h @@ -0,0 +1,199 @@ +/* + * wpa_supplicant - WPA definitions + * Copyright (c) 2003-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_H +#define WPA_H + +#include "common.h" +#include "rom/ets_sys.h" +#include "wpa/defs.h" +#include "wpa/wpa_common.h" + +//#include "net80211/ieee80211_var.h" +//#include "net80211/ieee80211_node.h" + +#define WPA_SM_STATE(_sm) ((_sm)->wpa_state) + +struct wpa_sm; + +int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); + +#define WPA_ASSERT ASSERT + +struct install_key { + int mic_errors_seen; /* Michael MIC errors with the current PTK */ + int keys_cleared; + enum wpa_alg alg; + u8 addr[ETH_ALEN]; + int key_idx; + int set_tx; + u8 seq[10]; + u8 key[32]; +}; + +/** + * struct wpa_sm - Internal WPA state machine data + */ +struct wpa_sm { + u8 pmk[PMK_LEN]; + size_t pmk_len; + +// char *passphrase; //wlan password +// u8 *ssid; //wlan network name +// size_t ssid_len; + + struct wpa_ptk ptk, tptk; + int ptk_set, tptk_set; + u8 snonce[WPA_NONCE_LEN]; + u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */ + int renew_snonce; + u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN]; + int rx_replay_counter_set; + u8 request_counter[WPA_REPLAY_COUNTER_LEN]; + +// void *network_ctx; + + unsigned int pairwise_cipher; + unsigned int group_cipher; + unsigned int key_mgmt; + unsigned int mgmt_group_cipher; + + int rsn_enabled; /* Whether RSN is enabled in configuration */ + + int countermeasures; /*TKIP countermeasures state flag, 1:in countermeasures state*/ + os_timer_t cm_timer; + + u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */ + size_t assoc_wpa_ie_len; + + u8 eapol_version; + + int wpa_ptk_rekey; + u8 own_addr[ETH_ALEN]; + + u8 bssid[ETH_ALEN]; + + unsigned int proto; + enum wpa_states wpa_state; + + u8 *ap_wpa_ie, *ap_rsn_ie; + size_t ap_wpa_ie_len, ap_rsn_ie_len; + + bool key_install; //Fix 4-way-handshake reinstall key vulnerability + struct install_key install_ptk; + struct install_key install_gtk; + int key_entry_valid; //present current avaliable entry for bssid, for pairkey:0,5,10,15,20, gtk: pairkey_no+i (i:1~4) + +// char *msg; //send eapol msg buff +// size_t msg_len; //msg length:6 + sizeof(eth) + data_len + +// struct netif *ifp; + uint8_t *wpadata; + uint16_t wpadatalen; + uint8_t flags; + + void (* sendto) (u8 *wpadata, u16 wpadatalen); + void (*config_assoc_ie) (uint8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); + void (*install_ppkey) (enum wpa_alg alg, uint8 *addr, int key_idx, int set_tx, + uint8 *seq, size_t seq_len, uint8 *key, size_t key_len, int key_entry_valid); + int (*get_ppkey) (uint8 *ifx, int *alg, uint8 *addr, int *key_idx, + uint8 *key, size_t key_len, int key_entry_valid); + void (*wpa_deauthenticate)(uint8 reason_code); + void (*wpa_neg_complete)(); + struct wpa_gtk_data gd; //used for calllback save param + uint16 key_info; //used for txcallback param +}; + +struct l2_ethhdr { + u8 h_dest[ETH_ALEN]; + u8 h_source[ETH_ALEN]; + be16 h_proto; +} STRUCT_PACKED; + +/** + * set_key - Configure encryption key + * @ifname: Interface name (for multi-SSID/VLAN support) + * @priv: private driver interface data + * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, + * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK); + * %WPA_ALG_NONE clears the key. + * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for + * broadcast/default keys + * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for + * IGTK + * @set_tx: configure this key as the default Tx key (only used when + * driver does not support separate unicast/individual key + * @seq: sequence number/packet number, seq_len octets, the next + * packet number to be used for in replay protection; configured + * for Rx keys (in most cases, this is only used with broadcast + * keys and set to zero for unicast keys) + * @seq_len: length of the seq, depends on the algorithm: + * TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets + * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, + * 8-byte Rx Mic Key + * @key_len: length of the key buffer in octets (WEP: 5 or 13, + * TKIP: 32, CCMP: 16, IGTK: 16) + * + * Returns: 0 on success, -1 on failure + * + * Configure the given key for the kernel driver. If the driver + * supports separate individual keys (4 default keys + 1 individual), + * addr can be used to determine whether the key is default or + * individual. If only 4 keys are supported, the default key with key + * index 0 is used as the individual key. STA must be configured to use + * it as the default Tx key (set_tx is set) and accept Rx for all the + * key indexes. In most cases, WPA uses only key indexes 1 and 2 for + * broadcast keys, so key index 0 is available for this kind of + * configuration. + * + * Please note that TKIP keys include separate TX and RX MIC keys and + * some drivers may expect them in different order than wpa_supplicant + * is using. If the TX/RX keys are swapped, all TKIP encrypted packets + * will tricker Michael MIC errors. This can be fixed by changing the + * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key + * in driver_*.c set_key() implementation, see driver_ndis.c for an + * example on how this can be done. + */ + + +/** + * send_eapol - Optional function for sending EAPOL packets + * @priv: private driver interface data + * @dest: Destination MAC address + * @proto: Ethertype + * @data: EAPOL packet starting with IEEE 802.1X header + * @data_len: Size of the EAPOL packet + * + * Returns: 0 on success, -1 on failure + * + * This optional function can be used to override l2_packet operations + * with driver specific functionality. If this function pointer is set, + * l2_packet module is not used at all and the driver interface code is + * responsible for receiving and sending all EAPOL packets. The + * received EAPOL packets are sent to core code with EVENT_EAPOL_RX + * event. The driver interface is required to implement get_mac_addr() + * handler if send_eapol() is used. + */ + +#define KEYENTRY_TABLE_MAP(key_entry_valid) ((key_entry_valid)%5) + +void pp_michael_mic_failure(uint16 isunicast); + +void wpa_sm_set_state(enum wpa_states state); + +int ppGetKey(uint8 *ifx, int *alg, uint8 *addr, int *key_idx, + uint8 *key, size_t key_len, int key_entry_valid); + +#endif /* WPA_H */ + diff --git a/components/wpa_supplicant/include/wpa/wpa_auth.h b/components/wpa_supplicant/include/wpa/wpa_auth.h new file mode 100755 index 00000000..c7299234 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_auth.h @@ -0,0 +1,292 @@ +/* + * hostapd - IEEE 802.11i-2004 / WPA Authenticator + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_AUTH_H +#define WPA_AUTH_H + +#include "wpa/defs.h" +#include "wpa/eapol_common.h" +#include "wpa/wpa_common.h" + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +/* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition + */ +struct ft_rrb_frame { + u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ + u8 packet_type; /* FT_PACKET_REQUEST/FT_PACKET_RESPONSE */ + le16 action_length; /* little endian length of action_frame */ + u8 ap_address[ETH_ALEN]; + /* + * Followed by action_length bytes of FT Action frame (from Category + * field to the end of Action Frame body. + */ +} STRUCT_PACKED; + +#define RSN_REMOTE_FRAME_TYPE_FT_RRB 1 + +#define FT_PACKET_REQUEST 0 +#define FT_PACKET_RESPONSE 1 +/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */ +#define FT_PACKET_R0KH_R1KH_PULL 200 +#define FT_PACKET_R0KH_R1KH_RESP 201 +#define FT_PACKET_R0KH_R1KH_PUSH 202 + +#define FT_R0KH_R1KH_PULL_DATA_LEN 44 +#define FT_R0KH_R1KH_RESP_DATA_LEN 76 +#define FT_R0KH_R1KH_PUSH_DATA_LEN 88 + +struct ft_r0kh_r1kh_pull_frame { + u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ + u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */ + le16 data_length; /* little endian length of data (44) */ + u8 ap_address[ETH_ALEN]; + + u8 nonce[16]; + u8 pmk_r0_name[WPA_PMK_NAME_LEN]; + u8 r1kh_id[FT_R1KH_ID_LEN]; + u8 s1kh_id[ETH_ALEN]; + u8 pad[4]; /* 8-octet boundary for AES key wrap */ + u8 key_wrap_extra[8]; +} STRUCT_PACKED; + +struct ft_r0kh_r1kh_resp_frame { + u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ + u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */ + le16 data_length; /* little endian length of data (76) */ + u8 ap_address[ETH_ALEN]; + + u8 nonce[16]; /* copied from pull */ + u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */ + u8 s1kh_id[ETH_ALEN]; /* copied from pull */ + u8 pmk_r1[PMK_LEN]; + u8 pmk_r1_name[WPA_PMK_NAME_LEN]; + le16 pairwise; + u8 pad[2]; /* 8-octet boundary for AES key wrap */ + u8 key_wrap_extra[8]; +} STRUCT_PACKED; + +struct ft_r0kh_r1kh_push_frame { + u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ + u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */ + le16 data_length; /* little endian length of data (88) */ + u8 ap_address[ETH_ALEN]; + + /* Encrypted with AES key-wrap */ + u8 timestamp[4]; /* current time in seconds since unix epoch, little + * endian */ + u8 r1kh_id[FT_R1KH_ID_LEN]; + u8 s1kh_id[ETH_ALEN]; + u8 pmk_r0_name[WPA_PMK_NAME_LEN]; + u8 pmk_r1[PMK_LEN]; + u8 pmk_r1_name[WPA_PMK_NAME_LEN]; + le16 pairwise; + u8 pad[6]; /* 8-octet boundary for AES key wrap */ + u8 key_wrap_extra[8]; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + +/* per STA state machine data */ + +struct wpa_authenticator; +struct wpa_state_machine; +struct rsn_pmksa_cache_entry; +struct eapol_state_machine; + + +struct ft_remote_r0kh { + struct ft_remote_r0kh *next; + u8 addr[ETH_ALEN]; + u8 id[FT_R0KH_ID_MAX_LEN]; + size_t id_len; + u8 key[16]; +}; + + +struct ft_remote_r1kh { + struct ft_remote_r1kh *next; + u8 addr[ETH_ALEN]; + u8 id[FT_R1KH_ID_LEN]; + u8 key[16]; +}; + + +struct wpa_auth_config { + int wpa; + int wpa_key_mgmt; + int wpa_pairwise; + int wpa_group; + int wpa_group_rekey; + int wpa_strict_rekey; + int wpa_gmk_rekey; + int wpa_ptk_rekey; + int rsn_pairwise; + int rsn_preauth; + int eapol_version; + int peerkey; + int wmm_enabled; + int wmm_uapsd; + int disable_pmksa_caching; + int okc; + int tx_status; +#ifdef CONFIG_IEEE80211W + enum mfp_options ieee80211w; +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211R +#define SSID_LEN 32 + u8 ssid[SSID_LEN]; + size_t ssid_len; + u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; + u8 r0_key_holder[FT_R0KH_ID_MAX_LEN]; + size_t r0_key_holder_len; + u8 r1_key_holder[FT_R1KH_ID_LEN]; + u32 r0_key_lifetime; + u32 reassociation_deadline; + struct ft_remote_r0kh *r0kh_list; + struct ft_remote_r1kh *r1kh_list; + int pmk_r1_push; + int ft_over_ds; +#endif /* CONFIG_IEEE80211R */ + int disable_gtk; + int ap_mlme; +}; + +typedef enum { + LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING +} logger_level; + +typedef enum { + WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized, + WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable, + WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx +} wpa_eapol_variable; + +struct wpa_auth_callbacks { + void *ctx; + void (*logger)(void *ctx, const u8 *addr, logger_level level, + const char *txt); + void (*disconnect)(void *ctx, const u8 *addr, u16 reason); + int (*mic_failure_report)(void *ctx, const u8 *addr); + void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var, + int value); + int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var); + const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk); + int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len); + int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg, + const u8 *addr, int idx, u8 *key, size_t key_len); + int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq); + int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data, + size_t data_len, int encrypt); + int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm, + void *ctx), void *cb_ctx); + int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a, + void *ctx), void *cb_ctx); + int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data, + size_t data_len); +#ifdef CONFIG_IEEE80211R + struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr); + int (*send_ft_action)(void *ctx, const u8 *dst, + const u8 *data, size_t data_len); + int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie, + size_t tspec_ielen); +#endif /* CONFIG_IEEE80211R */ +}; + +struct wpa_authenticator * wpa_init(const u8 *addr, + struct wpa_auth_config *conf, + struct wpa_auth_callbacks *cb); +int wpa_init_keys(struct wpa_authenticator *wpa_auth); +void wpa_deinit(struct wpa_authenticator *wpa_auth); +int wpa_reconfig(struct wpa_authenticator *wpa_auth, + struct wpa_auth_config *conf); + +enum { + WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE, + WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL, + WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER, + WPA_INVALID_MDIE, WPA_INVALID_PROTO +}; + +int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + const u8 *wpa_ie, size_t wpa_ie_len/*, + const u8 *mdie, size_t mdie_len*/); +int wpa_auth_uses_mfp(struct wpa_state_machine *sm); +struct wpa_state_machine * +wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr); +int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm); +void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm); +void wpa_auth_sta_deinit(struct wpa_state_machine *sm); +void wpa_receive(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + u8 *data, size_t data_len); +typedef enum { + WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH, + WPA_REAUTH_EAPOL, WPA_ASSOC_FT +} wpa_event; +void wpa_remove_ptk(struct wpa_state_machine *sm); +int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event); +void wpa_auth_sm_notify(struct wpa_state_machine *sm); +void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth); +int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen); +int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen); +void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth); +int wpa_auth_pairwise_set(struct wpa_state_machine *sm); +int wpa_auth_get_pairwise(struct wpa_state_machine *sm); +int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm); +int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm); +int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, + struct rsn_pmksa_cache_entry *entry); +struct rsn_pmksa_cache_entry * +wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm); +void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm); +const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, + size_t *len); +int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, + int session_timeout, struct eapol_state_machine *eapol); +int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, + const u8 *pmk, size_t len, const u8 *sta_addr, + int session_timeout, + struct eapol_state_machine *eapol); +int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id); +void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int ack); + +#ifdef CONFIG_IEEE80211R +u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, + size_t max_len, int auth_alg, + const u8 *req_ies, size_t req_ies_len); +void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, + u16 auth_transaction, const u8 *ies, size_t ies_len, + void (*cb)(void *ctx, const u8 *dst, const u8 *bssid, + u16 auth_transaction, u16 resp, + const u8 *ies, size_t ies_len), + void *ctx); +u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, + size_t ies_len); +int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len); +int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, + const u8 *data, size_t data_len); +void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr); +#endif /* CONFIG_IEEE80211R */ + +void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm); +void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag); +int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos); +int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos); + +int wpa_auth_uses_sae(struct wpa_state_machine *sm); + +#endif /* WPA_AUTH_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa_auth_i.h b/components/wpa_supplicant/include/wpa/wpa_auth_i.h new file mode 100755 index 00000000..86efcfe1 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_auth_i.h @@ -0,0 +1,235 @@ +/* + * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_AUTH_I_H +#define WPA_AUTH_I_H + +/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */ +#define RSNA_MAX_EAPOL_RETRIES 4 + +struct wpa_group; + +struct wpa_stsl_negotiation { + struct wpa_stsl_negotiation *next; + u8 initiator[ETH_ALEN]; + u8 peer[ETH_ALEN]; +}; + + +struct wpa_state_machine { + struct wpa_authenticator *wpa_auth; + struct wpa_group *group; + + u8 addr[ETH_ALEN]; + + enum { + WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED, + WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2, + WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART, + WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2, + WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE + } wpa_ptk_state; + + enum { + WPA_PTK_GROUP_IDLE = 0, + WPA_PTK_GROUP_REKEYNEGOTIATING, + WPA_PTK_GROUP_REKEYESTABLISHED, + WPA_PTK_GROUP_KEYERROR + } wpa_ptk_group_state; + + Boolean Init; + Boolean DeauthenticationRequest; + Boolean AuthenticationRequest; + Boolean ReAuthenticationRequest; + Boolean Disconnect; + int TimeoutCtr; + int GTimeoutCtr; + Boolean TimeoutEvt; + Boolean EAPOLKeyReceived; + Boolean EAPOLKeyPairwise; + Boolean EAPOLKeyRequest; + Boolean MICVerified; + Boolean GUpdateStationKeys; + u8 ANonce[WPA_NONCE_LEN]; + u8 SNonce[WPA_NONCE_LEN]; + u8 PMK[PMK_LEN]; + struct wpa_ptk PTK; + Boolean PTK_valid; + Boolean pairwise_set; + int keycount; + Boolean Pair; + struct wpa_key_replay_counter { + u8 counter[WPA_REPLAY_COUNTER_LEN]; + Boolean valid; + } key_replay[RSNA_MAX_EAPOL_RETRIES], + prev_key_replay[RSNA_MAX_EAPOL_RETRIES]; + Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */ + Boolean PTKRequest; /* not in IEEE 802.11i state machine */ + Boolean has_GTK; + Boolean PtkGroupInit; /* init request for PTK Group state machine */ + + u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */ + size_t last_rx_eapol_key_len; + + unsigned int changed:1; + unsigned int in_step_loop:1; + unsigned int pending_deinit:1; + unsigned int started:1; + unsigned int mgmt_frame_prot:1; + unsigned int rx_eapol_key_secure:1; + unsigned int update_snonce:1; +#ifdef CONFIG_IEEE80211R + unsigned int ft_completed:1; + unsigned int pmk_r1_name_valid:1; +#endif /* CONFIG_IEEE80211R */ + unsigned int is_wnmsleep:1; + + u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN]; + int req_replay_counter_used; + + u8 *wpa_ie; + size_t wpa_ie_len; + + enum { + WPA_VERSION_NO_WPA = 0 /* WPA not used */, + WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */, + WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */ + } wpa; + int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ + int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */ +// struct rsn_pmksa_cache_entry *pmksa; + +// u32 dot11RSNAStatsTKIPLocalMICFailures; +// u32 dot11RSNAStatsTKIPRemoteMICFailures; + +#ifdef CONFIG_IEEE80211R + u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */ + size_t xxkey_len; + u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth + * Request */ + u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */ + size_t r0kh_id_len; + u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key + * message 2/4 */ + u8 *assoc_resp_ftie; +#endif /* CONFIG_IEEE80211R */ + + int pending_1_of_4_timeout; + u32 index; +}; + + +/* per group key state machine data */ +struct wpa_group { + struct wpa_group *next; + int vlan_id; + + Boolean GInit; + int GKeyDoneStations; + Boolean GTKReKey; + int GTK_len; + int GN, GM; + Boolean GTKAuthenticator; + u8 Counter[WPA_NONCE_LEN]; + + enum { + WPA_GROUP_GTK_INIT = 0, + WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE + } wpa_group_state; + + u8 GMK[WPA_GMK_LEN]; + u8 GTK[2][WPA_GTK_MAX_LEN]; + u8 GNonce[WPA_NONCE_LEN]; + Boolean changed; + Boolean first_sta_seen; + Boolean reject_4way_hs_for_entropy; +#ifdef CONFIG_IEEE80211W + u8 IGTK[2][WPA_IGTK_LEN]; + int GN_igtk, GM_igtk; +#endif /* CONFIG_IEEE80211W */ +}; + + +struct wpa_ft_pmk_cache; + +/* per authenticator data */ +struct wpa_authenticator { + struct wpa_group *group; + +// unsigned int dot11RSNAStatsTKIPRemoteMICFailures; +// u32 dot11RSNAAuthenticationSuiteSelected; +// u32 dot11RSNAPairwiseCipherSelected; +// u32 dot11RSNAGroupCipherSelected; +// u8 dot11RSNAPMKIDUsed[PMKID_LEN]; +// u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */ +// u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */ +// u32 dot11RSNAGroupCipherRequested; /* FIX: update */ +// unsigned int dot11RSNATKIPCounterMeasuresInvoked; +// unsigned int dot11RSNA4WayHandshakeFailures; + +// struct wpa_stsl_negotiation *stsl_negotiations; + + struct wpa_auth_config conf; +// struct wpa_auth_callbacks cb; + + u8 *wpa_ie; + size_t wpa_ie_len; + + u8 addr[ETH_ALEN]; + +// struct rsn_pmksa_cache *pmksa; +// struct wpa_ft_pmk_cache *ft_pmk_cache; +}; + + +int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, + const u8 *pmkid); +#if 0 +void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr, + logger_level level, const char *txt); +void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, + logger_level level, const char *fmt, ...); +#endif +void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int key_info, + const u8 *key_rsc, const u8 *nonce, + const u8 *kde, size_t kde_len, + int keyidx, int encr, int force_version); +int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, + int (*cb)(struct wpa_state_machine *sm, void *ctx), + void *cb_ctx); +int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, + int (*cb)(struct wpa_authenticator *a, void *ctx), + void *cb_ctx); + +#ifdef CONFIG_PEERKEY +int wpa_stsl_remove(struct wpa_authenticator *wpa_auth, + struct wpa_stsl_negotiation *neg); +void wpa_smk_error(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, struct wpa_eapol_key *key); +void wpa_smk_m1(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, struct wpa_eapol_key *key); +void wpa_smk_m3(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, struct wpa_eapol_key *key); +#endif /* CONFIG_PEERKEY */ + +#ifdef CONFIG_IEEE80211R +int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len); +int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id, + size_t r0kh_id_len, + const u8 *anonce, const u8 *snonce, + u8 *buf, size_t len, const u8 *subelem, + size_t subelem_len); +int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, + struct wpa_ptk *ptk, size_t ptk_len); +struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void); +void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache); +void wpa_ft_install_ptk(struct wpa_state_machine *sm); +#endif /* CONFIG_IEEE80211R */ + +#endif /* WPA_AUTH_I_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa_auth_ie.h b/components/wpa_supplicant/include/wpa/wpa_auth_ie.h new file mode 100755 index 00000000..49991395 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_auth_ie.h @@ -0,0 +1,50 @@ +/* + * hostapd - WPA/RSN IE and KDE definitions + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_AUTH_IE_H +#define WPA_AUTH_IE_H + +struct wpa_eapol_ie_parse { + const u8 *wpa_ie; + size_t wpa_ie_len; + const u8 *rsn_ie; + size_t rsn_ie_len; + const u8 *pmkid; + const u8 *gtk; + size_t gtk_len; + const u8 *mac_addr; + size_t mac_addr_len; +#ifdef CONFIG_PEERKEY + const u8 *smk; + size_t smk_len; + const u8 *nonce; + size_t nonce_len; + const u8 *lifetime; + size_t lifetime_len; + const u8 *error; + size_t error_len; +#endif /* CONFIG_PEERKEY */ +#ifdef CONFIG_IEEE80211W + const u8 *igtk; + size_t igtk_len; +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211R + const u8 *mdie; + size_t mdie_len; + const u8 *ftie; + size_t ftie_len; +#endif /* CONFIG_IEEE80211R */ +}; + +int wpa_parse_kde_ies(const u8 *buf, size_t len, + struct wpa_eapol_ie_parse *ie); +u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, + const u8 *data2, size_t data2_len); +int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth); + +#endif /* WPA_AUTH_IE_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa_common.h b/components/wpa_supplicant/include/wpa/wpa_common.h new file mode 100755 index 00000000..480cf0e2 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_common.h @@ -0,0 +1,332 @@ +/* + * WPA definitions shared between hostapd and wpa_supplicant + * Copyright (c) 2002-2008, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "os.h" +#ifndef WPA_COMMON_H +#define WPA_COMMON_H + +#define WPA_MAX_SSID_LEN 32 + +/* IEEE 802.11i */ +#define PMKID_LEN 16 +#define PMK_LEN 32 +#define WPA_REPLAY_COUNTER_LEN 8 +#define WPA_NONCE_LEN 32 +#define WPA_KEY_RSC_LEN 8 +#define WPA_GMK_LEN 32 +#define WPA_GTK_MAX_LEN 32 + +#define WPA_SELECTOR_LEN 4 +#define WPA_VERSION 1 +#define RSN_SELECTOR_LEN 4 +#define RSN_VERSION 1 + +#define RSN_SELECTOR(a, b, c, d) \ + ((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \ + (u32) (d)) + +#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) +#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1) +#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2) +#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) +#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1) +#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2) +#if 0 +#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3) +#endif +#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4) +#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5) + + +#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1) +#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2) +#ifdef CONFIG_IEEE80211R +#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3) +#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4) +#endif /* CONFIG_IEEE80211R */ +#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) +#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6) + +#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) +#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1) +#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2) +#if 0 +#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3) +#endif +#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4) +#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) +#ifdef CONFIG_IEEE80211W +#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6) +#endif /* CONFIG_IEEE80211W */ +#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7) +#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8) + +/* EAPOL-Key Key Data Encapsulation + * GroupKey and PeerKey require encryption, otherwise, encryption is optional. + */ +#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1) +#if 0 +#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2) +#endif +#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3) +#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4) +#ifdef CONFIG_PEERKEY +#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5) +#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6) +#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7) +#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8) +#endif /* CONFIG_PEERKEY */ +#ifdef CONFIG_IEEE80211W +#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9) +#endif /* CONFIG_IEEE80211W */ + +#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1) + +#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val)) +#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a)) + +#define RSN_NUM_REPLAY_COUNTERS_1 0 +#define RSN_NUM_REPLAY_COUNTERS_2 1 +#define RSN_NUM_REPLAY_COUNTERS_4 2 +#define RSN_NUM_REPLAY_COUNTERS_16 3 + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +#ifdef CONFIG_IEEE80211W +#define WPA_IGTK_LEN 16 +#endif /* CONFIG_IEEE80211W */ + + +/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */ +#define WPA_CAPABILITY_PREAUTH BIT(0) +#define WPA_CAPABILITY_NO_PAIRWISE BIT(1) +/* B2-B3: PTKSA Replay Counter */ +/* B4-B5: GTKSA Replay Counter */ +#define WPA_CAPABILITY_MFPR BIT(6) +#define WPA_CAPABILITY_MFPC BIT(7) +#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9) + + +/* IEEE 802.11r */ +#define MOBILITY_DOMAIN_ID_LEN 2 +#define FT_R0KH_ID_MAX_LEN 48 +#define FT_R1KH_ID_LEN 6 +#define WPA_PMK_NAME_LEN 16 + + +/* IEEE 802.11, 8.5.2 EAPOL-Key frames */ +#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2))) +#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0) +#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1) +#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3 +#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ +/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */ +#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5)) +#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 +#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */ +#define WPA_KEY_INFO_TXRX BIT(6) /* group */ +#define WPA_KEY_INFO_ACK BIT(7) +#define WPA_KEY_INFO_MIC BIT(8) +#define WPA_KEY_INFO_SECURE BIT(9) +#define WPA_KEY_INFO_ERROR BIT(10) +#define WPA_KEY_INFO_REQUEST BIT(11) +#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */ +#define WPA_KEY_INFO_SMK_MESSAGE BIT(13) + + +struct wpa_eapol_key { + u8 type; + /* Note: key_info, key_length, and key_data_length are unaligned */ + u8 key_info[2]; /* big endian */ + u8 key_length[2]; /* big endian */ + u8 replay_counter[WPA_REPLAY_COUNTER_LEN]; + u8 key_nonce[WPA_NONCE_LEN]; + u8 key_iv[16]; + u8 key_rsc[WPA_KEY_RSC_LEN]; + u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */ + u8 key_mic[16]; + u8 key_data_length[2]; /* big endian */ + /* followed by key_data_length bytes of key_data */ +} STRUCT_PACKED; + +/** + * struct wpa_ptk - WPA Pairwise Transient Key + * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy + */ +struct wpa_ptk { + u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */ + u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */ + u8 tk1[16]; /* Temporal Key 1 (TK1) */ + union { + u8 tk2[16]; /* Temporal Key 2 (TK2) */ + struct { + u8 tx_mic_key[8]; + u8 rx_mic_key[8]; + } auth; + } u; +} STRUCT_PACKED; + +struct wpa_gtk_data { + enum wpa_alg alg; + int tx, key_rsc_len, keyidx; + u8 gtk[32]; + int gtk_len; +}; + + +/* WPA IE version 1 + * 00-50-f2:1 (OUI:OUI type) + * 0x01 0x00 (version; little endian) + * (all following fields are optional:) + * Group Suite Selector (4 octets) (default: TKIP) + * Pairwise Suite Count (2 octets, little endian) (default: 1) + * Pairwise Suite List (4 * n octets) (default: TKIP) + * Authenticated Key Management Suite Count (2 octets, little endian) + * (default: 1) + * Authenticated Key Management Suite List (4 * n octets) + * (default: unspec 802.1X) + * WPA Capabilities (2 octets, little endian) (default: 0) + */ + +struct wpa_ie_hdr { + u8 elem_id; + u8 len; + u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ + u8 version[2]; /* little endian */ +} STRUCT_PACKED; + + +/* 1/4: PMKID + * 2/4: RSN IE + * 3/4: one or two RSN IEs + GTK IE (encrypted) + * 4/4: empty + * 1/2: GTK IE (encrypted) + * 2/2: empty + */ + +/* RSN IE version 1 + * 0x01 0x00 (version; little endian) + * (all following fields are optional:) + * Group Suite Selector (4 octets) (default: CCMP) + * Pairwise Suite Count (2 octets, little endian) (default: 1) + * Pairwise Suite List (4 * n octets) (default: CCMP) + * Authenticated Key Management Suite Count (2 octets, little endian) + * (default: 1) + * Authenticated Key Management Suite List (4 * n octets) + * (default: unspec 802.1X) + * RSN Capabilities (2 octets, little endian) (default: 0) + * PMKID Count (2 octets) (default: 0) + * PMKID List (16 * n octets) + * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC) + */ + +struct rsn_ie_hdr { + u8 elem_id; /* WLAN_EID_RSN */ + u8 len; + u8 version[2]; /* little endian */ +} STRUCT_PACKED; + + +#ifdef CONFIG_PEERKEY +enum { + STK_MUI_4WAY_STA_AP = 1, + STK_MUI_4WAY_STAT_STA = 2, + STK_MUI_GTK = 3, + STK_MUI_SMK = 4 +}; + +enum { + STK_ERR_STA_NR = 1, + STK_ERR_STA_NRSN = 2, + STK_ERR_CPHR_NS = 3, + STK_ERR_NO_STSL = 4 +}; +#endif /* CONFIG_PEERKEY */ + +struct rsn_error_kde { + be16 mui; + be16 error_type; +} STRUCT_PACKED; + +#ifdef CONFIG_IEEE80211W +struct wpa_igtk_kde { + u8 keyid[2]; + u8 pn[6]; + u8 igtk[WPA_IGTK_LEN]; +} STRUCT_PACKED; +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_IEEE80211R +struct rsn_mdie { + u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; + u8 ft_capab; +} STRUCT_PACKED; + +#define RSN_FT_CAPAB_FT_OVER_DS BIT(0) +#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1) + +struct rsn_ftie { + u8 mic_control[2]; + u8 mic[16]; + u8 anonce[WPA_NONCE_LEN]; + u8 snonce[WPA_NONCE_LEN]; + /* followed by optional parameters */ +} STRUCT_PACKED; + +#define FTIE_SUBELEM_R1KH_ID 1 +#define FTIE_SUBELEM_GTK 2 +#define FTIE_SUBELEM_R0KH_ID 3 +#define FTIE_SUBELEM_IGTK 4 + +struct rsn_rdie { + u8 id; + u8 descr_count; + le16 status_code; +} STRUCT_PACKED; + +#endif /* CONFIG_IEEE80211R */ + +struct wpa_ie_data { + int proto; + int pairwise_cipher; + int group_cipher; + int key_mgmt; + int capabilities; + size_t num_pmkid; + const u8 *pmkid; + int mgmt_group_cipher; +}; + +const char * wpa_cipher_txt(int cipher); + +int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, + struct wpa_ie_data *data); + +int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, + u8 *mic); +int wpa_compare_rsn_ie(int ft_initial_assoc, + const u8 *ie1, size_t ie1len, + const u8 *ie2, size_t ie2len); + +void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, + const u8 *addr1, const u8 *addr2, + const u8 *nonce1, const u8 *nonce2, + u8 *ptk, size_t ptk_len, int use_sha256); + +void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, + u8 *pmkid, int use_sha256); + +#endif /* WPA_COMMON_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa_debug.1.h b/components/wpa_supplicant/include/wpa/wpa_debug.1.h new file mode 100755 index 00000000..ce068a26 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_debug.1.h @@ -0,0 +1,203 @@ +/* + * wpa_supplicant/hostapd / Debug prints + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_DEBUG_H +#define WPA_DEBUG_H + + +enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR }; + +/** EAP authentication completed successfully */ +#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS " + +int wpa_debug_open_file(const char *path); +void wpa_debug_close_file(void); + +/** + * wpa_debug_printf_timestamp - Print timestamp for debug output + * + * This function prints a timestamp in seconds_from_1970.microsoconds + * format if debug output has been configured to include timestamps in debug + * messages. + */ +void wpa_debug_print_timestamp(void); + +/** + * wpa_printf - conditional printf + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +#define DEBUG_PRINT +//#define MSG_PRINT + +/** + * wpa_hexdump - conditional hex dump + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump. + */ +#include "log.h" +#if 0 +#ifdef DEBUG_PRINT +#define wpa_printf(level,fmt, args...) ets_printf(fmt,## args) + +static inline void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) +{ + +} + +static inline void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, size_t len) +{ +} + + +void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len); + +static inline void wpa_hexdump_buf(int level, const char *title, + const struct wpabuf *buf) +{ + wpa_hexdump(level, title, wpabuf_head(buf), wpabuf_len(buf)); +} + +/** + * wpa_hexdump_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump. This works + * like wpa_hexdump(), but by default, does not include secret keys (passwords, + * etc.) in debug output. + */ +void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); + + +static inline void wpa_hexdump_buf_key(int level, const char *title, + const struct wpabuf *buf) +{ + wpa_hexdump_key(level, title, wpabuf_head(buf), wpabuf_len(buf)); +} + +/** + * wpa_hexdump_ascii - conditional hex dump + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump with both + * the hex numbers and ASCII characters (for printable range) are shown. 16 + * bytes per line will be shown. + */ +void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, + size_t len); + +/** + * wpa_hexdump_ascii_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump with both + * the hex numbers and ASCII characters (for printable range) are shown. 16 + * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by + * default, does not include secret keys (passwords, etc.) in debug output. + */ +void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, + size_t len); +#else +#define wpa_printf(level, ...) +#define wpa_hexdump +#define wpa_hexdump_buf +#define wpa_hexdump_key +#define wpa_hexdump_buf_key +#define wpa_hexdump_ascii +#define wpa_hexdump_ascii_key +#endif +#else +#define wpa_printf(level, ...) WLOGD(MWIFI, SWPA, ##__VA_ARGS__) +#define wpa_hexdump +#define wpa_hexdump_buf +#define wpa_hexdump_key +#define wpa_hexdump_buf_key +#define wpa_hexdump_ascii +#define wpa_hexdump_ascii_key +#endif +#define wpa_auth_logger +#define wpa_auth_vlogger + +/** + * wpa_msg - Conditional printf for default target and ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. This function is like wpa_printf(), but it also sends the + * same message to all attached ctrl_iface monitors. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it sends the output only to the + * attached ctrl_iface monitors. In other words, it can be used for frequent + * events that do not need to be sent to syslog. + */ +void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + +typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt, + size_t len); + +typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx); + +int eloop_cancel_timeout(eloop_timeout_handler handler, + void *eloop_data, void *user_data); + +int eloop_register_timeout(unsigned int secs, unsigned int usecs, + eloop_timeout_handler handler, + void *eloop_data, void *user_data); + + +#endif /* WPA_DEBUG_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa_i.h b/components/wpa_supplicant/include/wpa/wpa_i.h new file mode 100755 index 00000000..48e2bcb1 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_i.h @@ -0,0 +1,93 @@ +/* + * Internal WPA/RSN supplicant state machine definitions + * Copyright (c) 2004-2010, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_I_H +#define WPA_I_H + +/** + * set_key - Configure encryption key + * @ifname: Interface name (for multi-SSID/VLAN support) + * @priv: private driver interface data + * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, + * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK); + * %WPA_ALG_NONE clears the key. + * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for + * broadcast/default keys + * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for + * IGTK + * @set_tx: configure this key as the default Tx key (only used when + * driver does not support separate unicast/individual key + * @seq: sequence number/packet number, seq_len octets, the next + * packet number to be used for in replay protection; configured + * for Rx keys (in most cases, this is only used with broadcast + * keys and set to zero for unicast keys) + * @seq_len: length of the seq, depends on the algorithm: + * TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets + * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, + * 8-byte Rx Mic Key + * @key_len: length of the key buffer in octets (WEP: 5 or 13, + * TKIP: 32, CCMP: 16, IGTK: 16) + * + * Returns: 0 on success, -1 on failure + * + * Configure the given key for the kernel driver. If the driver + * supports separate individual keys (4 default keys + 1 individual), + * addr can be used to determine whether the key is default or + * individual. If only 4 keys are supported, the default key with key + * index 0 is used as the individual key. STA must be configured to use + * it as the default Tx key (set_tx is set) and accept Rx for all the + * key indexes. In most cases, WPA uses only key indexes 1 and 2 for + * broadcast keys, so key index 0 is available for this kind of + * configuration. + * + * Please note that TKIP keys include separate TX and RX MIC keys and + * some drivers may expect them in different order than wpa_supplicant + * is using. If the TX/RX keys are swapped, all TKIP encrypted packets + * will tricker Michael MIC errors. This can be fixed by changing the + * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key + * in driver_*.c set_key() implementation, see driver_ndis.c for an + * example on how this can be done. + */ + +typedef void (* WPA_SEND_FUNC)(uint8_t* wpadata, uint16_t wpadatalen); + +typedef void (* WPA_SET_ASSOC_IE)(uint8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); + +typedef void (*WPA_INSTALL_KEY) (enum wpa_alg alg, uint8 *addr, int key_idx, int set_tx, + uint8 *seq, size_t seq_len, uint8 *key, size_t key_len, int key_entry_valid); + +typedef int (*WPA_GET_KEY) (uint8 *ifx, int *alg, uint8 *addr, int *key_idx, + uint8 *key, size_t key_len, int key_entry_valid); + +typedef void (*WPA_DEAUTH)(uint8 reason_code); + +typedef void (*WPA_NEG_COMPLETE)(); + +void wpa_register(char * payload, WPA_SEND_FUNC snd_func, \ + WPA_SET_ASSOC_IE set_assoc_ie_func, \ + WPA_INSTALL_KEY ppinstallkey, \ + WPA_GET_KEY ppgetkey, \ + WPA_DEAUTH wpa_deauth, \ + WPA_NEG_COMPLETE wpa_neg_complete); + +#include "pp/esf_buf.h" +void eapol_txcb(esf_buf_t *eb); + +void wpa_set_profile(uint32 wpa_proto); + +void wpa_set_bss(char *macddr, char * bssid, uint8 pairwise_cipher, uint8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len); + +int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); +#endif /* WPA_I_H */ + diff --git a/components/wpa_supplicant/include/wpa/wpa_ie.h b/components/wpa_supplicant/include/wpa/wpa_ie.h new file mode 100755 index 00000000..94518d84 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_ie.h @@ -0,0 +1,56 @@ +/* + * wpa_supplicant - WPA/RSN IE and KDE definitions + * Copyright (c) 2004-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_IE_H +#define WPA_IE_H + +struct wpa_eapol_ie_parse { + const u8 *wpa_ie; + size_t wpa_ie_len; + const u8 *rsn_ie; + size_t rsn_ie_len; + const u8 *pmkid; + const u8 *gtk; + size_t gtk_len; + const u8 *mac_addr; + size_t mac_addr_len; +#ifdef CONFIG_PEERKEY + const u8 *smk; + size_t smk_len; + const u8 *nonce; + size_t nonce_len; + const u8 *lifetime; + size_t lifetime_len; + const u8 *error; + size_t error_len; +#endif /* CONFIG_PEERKEY */ +#ifdef CONFIG_IEEE80211W + const u8 *igtk; + size_t igtk_len; +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211R + const u8 *mdie; + size_t mdie_len; + const u8 *ftie; + size_t ftie_len; + const u8 *reassoc_deadline; + const u8 *key_lifetime; +#endif /* CONFIG_IEEE80211R */ +}; + +int wpa_supplicant_parse_ies(const u8 *buf, size_t len, + struct wpa_eapol_ie_parse *ie); +int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len); + +#endif /* WPA_IE_H */ diff --git a/components/wpa_supplicant/include/wpa/wpabuf.1.h b/components/wpa_supplicant/include/wpa/wpabuf.1.h new file mode 100755 index 00000000..cccfcc80 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpabuf.1.h @@ -0,0 +1,168 @@ +/* + * Dynamic data buffer + * Copyright (c) 2007-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPABUF_H +#define WPABUF_H + +/* + * Internal data structure for wpabuf. Please do not touch this directly from + * elsewhere. This is only defined in header file to allow inline functions + * from this file to access data. + */ +struct wpabuf { + size_t size; /* total size of the allocated buffer */ + size_t used; /* length of data in the buffer */ + u8 *ext_data; /* pointer to external data; NULL if data follows + * struct wpabuf */ + /* optionally followed by the allocated buffer */ +}; + + +int wpabuf_resize(struct wpabuf **buf, size_t add_len); +struct wpabuf * wpabuf_alloc(size_t len); +struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len); +struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len); +struct wpabuf * wpabuf_dup(const struct wpabuf *src); +void wpabuf_free(struct wpabuf *buf); +void * wpabuf_put(struct wpabuf *buf, size_t len); +struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); +struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); +void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3); + + +/** + * wpabuf_size - Get the currently allocated size of a wpabuf buffer + * @buf: wpabuf buffer + * Returns: Currently allocated size of the buffer + */ +static inline size_t wpabuf_size(const struct wpabuf *buf) +{ + return buf->size; +} + +/** + * wpabuf_len - Get the current length of a wpabuf buffer data + * @buf: wpabuf buffer + * Returns: Currently used length of the buffer + */ +static inline size_t wpabuf_len(const struct wpabuf *buf) +{ + return buf->used; +} + +/** + * wpabuf_tailroom - Get size of available tail room in the end of the buffer + * @buf: wpabuf buffer + * Returns: Tail room (in bytes) of available space in the end of the buffer + */ +static inline size_t wpabuf_tailroom(const struct wpabuf *buf) +{ + return buf->size - buf->used; +} + +/** + * wpabuf_head - Get pointer to the head of the buffer data + * @buf: wpabuf buffer + * Returns: Pointer to the head of the buffer data + */ +static inline const void * wpabuf_head(const struct wpabuf *buf) +{ + if (buf->ext_data) + return buf->ext_data; + return buf + 1; +} + +static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) +{ + return wpabuf_head(buf); +} + +/** + * wpabuf_mhead - Get modifiable pointer to the head of the buffer data + * @buf: wpabuf buffer + * Returns: Pointer to the head of the buffer data + */ +static inline void * wpabuf_mhead(struct wpabuf *buf) +{ + if (buf->ext_data) + return buf->ext_data; + return buf + 1; +} + +static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) +{ + return wpabuf_mhead(buf); +} + +static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) +{ + u8 *pos = wpabuf_put(buf, 1); + *pos = data; +} + +static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) +{ + u8 *pos = wpabuf_put(buf, 2); + WPA_PUT_LE16(pos, data); +} + +static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data) +{ + u8 *pos = wpabuf_put(buf, 4); + WPA_PUT_LE32(pos, data); +} + +static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) +{ + u8 *pos = wpabuf_put(buf, 2); + WPA_PUT_BE16(pos, data); +} + +static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data) +{ + u8 *pos = wpabuf_put(buf, 3); + WPA_PUT_BE24(pos, data); +} + +static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data) +{ + u8 *pos = wpabuf_put(buf, 4); + WPA_PUT_BE32(pos, data); +} + +static inline void wpabuf_put_data(struct wpabuf *buf, const void *data, + size_t len) +{ + if (data) + os_memcpy(wpabuf_put(buf, len), data, len); +} + +static inline void wpabuf_put_buf(struct wpabuf *dst, + const struct wpabuf *src) +{ + wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src)); +} + +static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len) +{ + buf->ext_data = (u8 *) data; + buf->size = buf->used = len; +} + +static inline void wpabuf_put_str(struct wpabuf *dst, const char *str) +{ + wpabuf_put_data(dst, str, os_strlen(str)); +} + +#endif /* WPABUF_H */ diff --git a/components/wpa_supplicant/include/wpa/wpas_glue.h b/components/wpa_supplicant/include/wpa/wpas_glue.h new file mode 100755 index 00000000..7e254a2d --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpas_glue.h @@ -0,0 +1,31 @@ +/* + * WPA Supplicant - Glue code to setup EAPOL and RSN modules + * Copyright (c) 2003-2008, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPAS_GLUE_H +#define WPAS_GLUE_H + +u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos); + +int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr, + int protect_type, int key_type); + +void wpa_sm_deauthenticate(struct wpa_sm *sm, uint8 reason_code); + +void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code); + +int wpa_sm_get_beacon_ie(struct wpa_sm *sm); + +#endif /* WPAS_GLUE_H */ diff --git a/components/wpa_supplicant/include/wps/asm/irqflags.h b/components/wpa_supplicant/include/wps/asm/irqflags.h new file mode 100644 index 00000000..dfe2f3ee --- /dev/null +++ b/components/wpa_supplicant/include/wps/asm/irqflags.h @@ -0,0 +1,58 @@ + + +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _IRQFLAGS_H +#define _IRQFLAGS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief save IRQ state and disable IRQ + * + * @return saved IRQ state + */ +static inline uint32_t arch_local_irq_save(void) +{ + uint32_t tmp; + + __asm__ __volatile__ ("rsil %0, 3" : "=a" (tmp) :: "memory"); + + return tmp; +} + +/** + * @brief restore IRQ state + * + * @param tmp saved IRQ state + */ +static inline void arch_local_irq_restore(uint32_t tmp) +{ + __asm__ __volatile__ ("wsr %0, ps" :: "a" (tmp) : "memory"); +} + +#define local_irq_declare(_t) uint32_t (_t) +#define local_irq_save(_t) (_t) = arch_local_irq_save() +#define local_irq_restore(_t) arch_local_irq_restore(_t) + +#ifdef __cplusplus +} +#endif + +#endif /* _IRQFLAGS_H */ diff --git a/components/wpa_supplicant/include/wps/utils/uuid.h b/components/wpa_supplicant/include/wps/utils/uuid.h new file mode 100644 index 00000000..5e860cbc --- /dev/null +++ b/components/wpa_supplicant/include/wps/utils/uuid.h @@ -0,0 +1,18 @@ +/* + * Universally Unique IDentifier (UUID) + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef UUID_H +#define UUID_H + +#define UUID_LEN 16 + +int uuid_str2bin(const char *str, u8 *bin); +int uuid_bin2str(const u8 *bin, char *str, size_t max_len); +int is_nil_uuid(const u8 *uuid); + +#endif /* UUID_H */ diff --git a/components/wpa_supplicant/include/wps/wps.h b/components/wpa_supplicant/include/wps/wps.h new file mode 100644 index 00000000..3db86556 --- /dev/null +++ b/components/wpa_supplicant/include/wps/wps.h @@ -0,0 +1,1066 @@ +/* + * Wi-Fi Protected Setup + * Copyright (c) 2007-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPS_H +#define WPS_H + +#include "wps/wps_defs.h" +#include "esp_wifi_types.h" + +/** + * enum wsc_op_code - EAP-WSC OP-Code values + */ +enum wsc_op_code { + WSC_UPnP = 0 /* No OP Code in UPnP transport */, + WSC_Start = 0x01, + WSC_ACK = 0x02, + WSC_NACK = 0x03, + WSC_MSG = 0x04, + WSC_Done = 0x05, + WSC_FRAG_ACK = 0x06 +}; + +struct wps_registrar; +//struct upnp_wps_device_sm; +struct wps_er; +struct wps_parse_attr; + +/** + * struct wps_credential - WPS Credential + * @ssid: SSID + * @ssid_len: Length of SSID + * @auth_type: Authentication Type (WPS_AUTH_OPEN, .. flags) + * @encr_type: Encryption Type (WPS_ENCR_NONE, .. flags) + * @key_idx: Key index + * @key: Key + * @key_len: Key length in octets + * @mac_addr: MAC address of the Credential receiver + * @cred_attr: Unparsed Credential attribute data (used only in cred_cb()); + * this may be %NULL, if not used + * @cred_attr_len: Length of cred_attr in octets + * @ap_channel: AP channel + */ +struct wps_credential { + u8 ssid[32]; + size_t ssid_len; + u16 auth_type; + u16 encr_type; + u8 key_idx; + u8 key[64]; + size_t key_len; + u8 mac_addr[ETH_ALEN]; + const u8 *cred_attr; + size_t cred_attr_len; + u16 ap_channel; +}; + +#define WPS_DEV_TYPE_LEN 8 +#define WPS_DEV_TYPE_BUFSIZE 21 +#define WPS_SEC_DEV_TYPE_MAX_LEN 128 +/* maximum number of advertised WPS vendor extension attributes */ +#define MAX_WPS_VENDOR_EXTENSIONS 10 +/* maximum size of WPS Vendor extension attribute */ +#define WPS_MAX_VENDOR_EXT_LEN 1024 +/* maximum number of parsed WPS vendor extension attributes */ +#define MAX_WPS_PARSE_VENDOR_EXT 10 + +/** + * struct wps_device_data - WPS Device Data + * @mac_addr: Device MAC address + * @device_name: Device Name (0..32 octets encoded in UTF-8) + * @manufacturer: Manufacturer (0..64 octets encoded in UTF-8) + * @model_name: Model Name (0..32 octets encoded in UTF-8) + * @model_number: Model Number (0..32 octets encoded in UTF-8) + * @serial_number: Serial Number (0..32 octets encoded in UTF-8) + * @pri_dev_type: Primary Device Type + * @sec_dev_type: Array of secondary device types + * @num_sec_dev_type: Number of secondary device types + * @os_version: OS Version + * @rf_bands: RF bands (WPS_RF_24GHZ, WPS_RF_50GHZ flags) + * @p2p: Whether the device is a P2P device + */ +struct wps_device_data { + u8 mac_addr[ETH_ALEN]; + char *device_name; + char *manufacturer; + char *model_name; + char *model_number; + char *serial_number; + u8 pri_dev_type[WPS_DEV_TYPE_LEN]; +#define WPS_SEC_DEVICE_TYPES 5 + u8 sec_dev_type[WPS_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN]; + u8 num_sec_dev_types; + u32 os_version; + u8 rf_bands; + u16 config_methods; + struct wpabuf *vendor_ext_m1; + struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; + + int p2p; +}; + +/** + * struct wps_config - WPS configuration for a single registration protocol run + */ +struct wps_config { + /** + * wps - Pointer to long term WPS context + */ + struct wps_context *wps; + + /** + * registrar - Whether this end is a Registrar + */ + int registrar; + + /** + * pin - Enrollee Device Password (%NULL for Registrar or PBC) + */ + const u8 *pin; + + /** + * pin_len - Length on pin in octets + */ + size_t pin_len; + + /** + * pbc - Whether this is protocol run uses PBC + */ + int pbc; + + /** + * assoc_wps_ie: (Re)AssocReq WPS IE (in AP; %NULL if not AP) + */ + const struct wpabuf *assoc_wps_ie; + + /** + * new_ap_settings - New AP settings (%NULL if not used) + * + * This parameter provides new AP settings when using a wireless + * stations as a Registrar to configure the AP. %NULL means that AP + * will not be reconfigured, i.e., the station will only learn the + * current AP settings by using AP PIN. + */ + const struct wps_credential *new_ap_settings; + + /** + * peer_addr: MAC address of the peer in AP; %NULL if not AP + */ + const u8 *peer_addr; + + /** + * use_psk_key - Use PSK format key in Credential + * + * Force PSK format to be used instead of ASCII passphrase when + * building Credential for an Enrollee. The PSK value is set in + * struct wpa_context::psk. + */ + int use_psk_key; + + /** + * dev_pw_id - Device Password ID for Enrollee when PIN is used + */ + u16 dev_pw_id; + + /** + * p2p_dev_addr - P2P Device Address from (Re)Association Request + * + * On AP/GO, this is set to the P2P Device Address of the associating + * P2P client if a P2P IE is included in the (Re)Association Request + * frame and the P2P Device Address is included. Otherwise, this is set + * to %NULL to indicate the station does not have a P2P Device Address. + */ + const u8 *p2p_dev_addr; + + /** + * pbc_in_m1 - Do not remove PushButton config method in M1 (AP) + * + * This can be used to enable a workaround to allow Windows 7 to use + * PBC with the AP. + */ + int pbc_in_m1; +}; + +/* Bssid of the discard AP which is discarded for not select reg or other reason */ +struct discard_ap_list_t{ + u8 bssid[6]; +}; + +//struct wps_data * wps_init(const struct wps_config *cfg); +struct wps_data * wps_init(void); + +//void wps_deinit(struct wps_data *data); +void wps_deinit(void); + +/** + * enum wps_process_res - WPS message processing result + */ +enum wps_process_res { + /** + * WPS_DONE - Processing done + */ + WPS_DONE, + + /** + * WPS_CONTINUE - Processing continues + */ + WPS_CONTINUE, + + /** + * WPS_FAILURE - Processing failed + */ + WPS_FAILURE, + + /** + * WPS_PENDING - Processing continues, but waiting for an external + * event (e.g., UPnP message from an external Registrar) + */ + WPS_PENDING, + WPS_IGNORE, /* snake, ignore the re-packge */ + + WPS_FRAGMENT /* Tim, send wsc fragment ack */ +}; +enum wps_process_res wps_process_msg(struct wps_data *wps, + enum wsc_op_code op_code, + const struct wpabuf *msg); + +struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code); + +int wps_is_selected_pbc_registrar(const struct wpabuf *msg, uint8_t *bssid); +#ifdef CONFIG_WPS_PIN +int wps_is_selected_pin_registrar(const struct wpabuf *msg, uint8_t *bssid); +#endif +int wps_ap_priority_compar(const struct wpabuf *wps_a, + const struct wpabuf *wps_b); +int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, + int ver1_compat); +const u8 * wps_get_uuid_e(const struct wpabuf *msg); +int wps_is_20(const struct wpabuf *msg); + +struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type); +struct wpabuf * wps_build_assoc_resp_ie(void); +struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev, + const u8 *uuid, + enum wps_request_type req_type, + unsigned int num_req_dev_types, + const u8 *req_dev_types); + + +/** + * struct wps_registrar_config - WPS Registrar configuration + */ +struct wps_registrar_config { + /** + * new_psk_cb - Callback for new PSK + * @ctx: Higher layer context data (cb_ctx) + * @mac_addr: MAC address of the Enrollee + * @psk: The new PSK + * @psk_len: The length of psk in octets + * Returns: 0 on success, -1 on failure + * + * This callback is called when a new per-device PSK is provisioned. + */ + int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk, + size_t psk_len); + + /** + * set_ie_cb - Callback for WPS IE changes + * @ctx: Higher layer context data (cb_ctx) + * @beacon_ie: WPS IE for Beacon + * @probe_resp_ie: WPS IE for Probe Response + * Returns: 0 on success, -1 on failure + * + * This callback is called whenever the WPS IE in Beacon or Probe + * Response frames needs to be changed (AP only). Callee is responsible + * for freeing the buffers. + */ + int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie, + struct wpabuf *probe_resp_ie); + + /** + * pin_needed_cb - Callback for requesting a PIN + * @ctx: Higher layer context data (cb_ctx) + * @uuid_e: UUID-E of the unknown Enrollee + * @dev: Device Data from the unknown Enrollee + * + * This callback is called whenever an unknown Enrollee requests to use + * PIN method and a matching PIN (Device Password) is not found in + * Registrar data. + */ + void (*pin_needed_cb)(void *ctx, const u8 *uuid_e, + const struct wps_device_data *dev); + + /** + * reg_success_cb - Callback for reporting successful registration + * @ctx: Higher layer context data (cb_ctx) + * @mac_addr: MAC address of the Enrollee + * @uuid_e: UUID-E of the Enrollee + * @dev_pw: Device Password (PIN) used during registration + * @dev_pw_len: Length of dev_pw in octets + * + * This callback is called whenever an Enrollee completes registration + * successfully. + */ + void (*reg_success_cb)(void *ctx, const u8 *mac_addr, + const u8 *uuid_e, const u8 *dev_pw, + size_t dev_pw_len); + + /** + * set_sel_reg_cb - Callback for reporting selected registrar changes + * @ctx: Higher layer context data (cb_ctx) + * @sel_reg: Whether the Registrar is selected + * @dev_passwd_id: Device Password ID to indicate with method or + * specific password the Registrar intends to use + * @sel_reg_config_methods: Bit field of active config methods + * + * This callback is called whenever the Selected Registrar state + * changes (e.g., a new PIN becomes available or PBC is invoked). This + * callback is only used by External Registrar implementation; + * set_ie_cb() is used by AP implementation in similar caes, but it + * provides the full WPS IE data instead of just the minimal Registrar + * state information. + */ + void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id, + u16 sel_reg_config_methods); + + /** + * enrollee_seen_cb - Callback for reporting Enrollee based on ProbeReq + * @ctx: Higher layer context data (cb_ctx) + * @addr: MAC address of the Enrollee + * @uuid_e: UUID of the Enrollee + * @pri_dev_type: Primary device type + * @config_methods: Config Methods + * @dev_password_id: Device Password ID + * @request_type: Request Type + * @dev_name: Device Name (if available) + */ + void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e, + const u8 *pri_dev_type, u16 config_methods, + u16 dev_password_id, u8 request_type, + const char *dev_name); + + /** + * cb_ctx: Higher layer context data for Registrar callbacks + */ + void *cb_ctx; + + /** + * skip_cred_build: Do not build credential + * + * This option can be used to disable internal code that builds + * Credential attribute into M8 based on the current network + * configuration and Enrollee capabilities. The extra_cred data will + * then be used as the Credential(s). + */ + int skip_cred_build; + + /** + * extra_cred: Additional Credential attribute(s) + * + * This optional data (set to %NULL to disable) can be used to add + * Credential attribute(s) for other networks into M8. If + * skip_cred_build is set, this will also override the automatically + * generated Credential attribute. + */ + const u8 *extra_cred; + + /** + * extra_cred_len: Length of extra_cred in octets + */ + size_t extra_cred_len; + + /** + * disable_auto_conf - Disable auto-configuration on first registration + * + * By default, the AP that is started in not configured state will + * generate a random PSK and move to configured state when the first + * registration protocol run is completed successfully. This option can + * be used to disable this functionality and leave it up to an external + * program to take care of configuration. This requires the extra_cred + * to be set with a suitable Credential and skip_cred_build being used. + */ + int disable_auto_conf; + + /** + * static_wep_only - Whether the BSS supports only static WEP + */ + int static_wep_only; + + /** + * dualband - Whether this is a concurrent dualband AP + */ + int dualband; +}; + + +/** + * enum wps_event - WPS event types + */ +enum wps_event { + /** + * WPS_EV_M2D - M2D received (Registrar did not know us) + */ + WPS_EV_M2D, + + /** + * WPS_EV_FAIL - Registration failed + */ + WPS_EV_FAIL, + + /** + * WPS_EV_SUCCESS - Registration succeeded + */ + WPS_EV_SUCCESS, + + /** + * WPS_EV_PWD_AUTH_FAIL - Password authentication failed + */ + WPS_EV_PWD_AUTH_FAIL, + + /** + * WPS_EV_PBC_OVERLAP - PBC session overlap detected + */ + WPS_EV_PBC_OVERLAP, + + /** + * WPS_EV_PBC_TIMEOUT - PBC walktime expired before protocol run start + */ + WPS_EV_PBC_TIMEOUT, + + /** + * WPS_EV_ER_AP_ADD - ER: AP added + */ + WPS_EV_ER_AP_ADD, + + /** + * WPS_EV_ER_AP_REMOVE - ER: AP removed + */ + WPS_EV_ER_AP_REMOVE, + + /** + * WPS_EV_ER_ENROLLEE_ADD - ER: Enrollee added + */ + WPS_EV_ER_ENROLLEE_ADD, + + /** + * WPS_EV_ER_ENROLLEE_REMOVE - ER: Enrollee removed + */ + WPS_EV_ER_ENROLLEE_REMOVE, + + /** + * WPS_EV_ER_AP_SETTINGS - ER: AP Settings learned + */ + WPS_EV_ER_AP_SETTINGS, + + /** + * WPS_EV_ER_SET_SELECTED_REGISTRAR - ER: SetSelectedRegistrar event + */ + WPS_EV_ER_SET_SELECTED_REGISTRAR, + + /** + * WPS_EV_AP_PIN_SUCCESS - External Registrar used correct AP PIN + */ + WPS_EV_AP_PIN_SUCCESS +}; + +/** + * union wps_event_data - WPS event data + */ +union wps_event_data { + /** + * struct wps_event_m2d - M2D event data + */ + struct wps_event_m2d { + u16 config_methods; + const u8 *manufacturer; + size_t manufacturer_len; + const u8 *model_name; + size_t model_name_len; + const u8 *model_number; + size_t model_number_len; + const u8 *serial_number; + size_t serial_number_len; + const u8 *dev_name; + size_t dev_name_len; + const u8 *primary_dev_type; /* 8 octets */ + u16 config_error; + u16 dev_password_id; + } m2d; + + /** + * struct wps_event_fail - Registration failure information + * @msg: enum wps_msg_type + */ + struct wps_event_fail { + int msg; + u16 config_error; + u16 error_indication; + } fail; + + struct wps_event_pwd_auth_fail { + int enrollee; + int part; + } pwd_auth_fail; + + struct wps_event_er_ap { + const u8 *uuid; + const u8 *mac_addr; + const char *friendly_name; + const char *manufacturer; + const char *manufacturer_url; + const char *model_description; + const char *model_name; + const char *model_number; + const char *model_url; + const char *serial_number; + const char *upc; + const u8 *pri_dev_type; + u8 wps_state; + } ap; + + struct wps_event_er_enrollee { + const u8 *uuid; + const u8 *mac_addr; + int m1_received; + u16 config_methods; + u16 dev_passwd_id; + const u8 *pri_dev_type; + const char *dev_name; + const char *manufacturer; + const char *model_name; + const char *model_number; + const char *serial_number; + } enrollee; + + struct wps_event_er_ap_settings { + const u8 *uuid; + const struct wps_credential *cred; + } ap_settings; + + struct wps_event_er_set_selected_registrar { + const u8 *uuid; + int sel_reg; + u16 dev_passwd_id; + u16 sel_reg_config_methods; + enum { + WPS_ER_SET_SEL_REG_START, + WPS_ER_SET_SEL_REG_DONE, + WPS_ER_SET_SEL_REG_FAILED + } state; + } set_sel_reg; +}; +#ifdef CONFIG_WPS_UPNP +/** + * struct upnp_pending_message - Pending PutWLANResponse messages + * @next: Pointer to next pending message or %NULL + * @addr: NewWLANEventMAC + * @msg: NewMessage + * @type: Message Type + */ +struct upnp_pending_message { + struct upnp_pending_message *next; + u8 addr[ETH_ALEN]; + struct wpabuf *msg; + enum wps_msg_type type; +}; +void wps_free_pending_msgs(struct upnp_pending_message *msgs); +#endif +/** + * struct wps_context - Long term WPS context data + * + * This data is stored at the higher layer Authenticator or Supplicant data + * structures and it is maintained over multiple registration protocol runs. + */ +struct wps_context { + /** + * ap - Whether the local end is an access point + */ + int ap; + + /** + * registrar - Pointer to WPS registrar data from wps_registrar_init() + */ + struct wps_registrar *registrar; + + /** + * wps_state - Current WPS state + */ + enum wps_state wps_state; + + /** + * ap_setup_locked - Whether AP setup is locked (only used at AP) + */ + int ap_setup_locked; + + /** + * uuid - Own UUID + */ + u8 uuid[16]; + + /** + * ssid - SSID + * + * This SSID is used by the Registrar to fill in information for + * Credentials. In addition, AP uses it when acting as an Enrollee to + * notify Registrar of the current configuration. + */ + u8 ssid[32]; + + /** + * ssid_len - Length of ssid in octets + */ + size_t ssid_len; + + /** + * dev - Own WPS device data + */ + struct wps_device_data dev; + + /** + * dh_ctx - Context data for Diffie-Hellman operation + */ + void *dh_ctx; + + /** + * dh_privkey - Diffie-Hellman private key + */ + struct wpabuf *dh_privkey; + + /** + * dh_pubkey_oob - Diffie-Hellman public key + */ + struct wpabuf *dh_pubkey; + + /** + * config_methods - Enabled configuration methods + * + * Bit field of WPS_CONFIG_* + */ + u16 config_methods; + + /** + * encr_types - Enabled encryption types (bit field of WPS_ENCR_*) + */ + u16 encr_types; + + /** + * auth_types - Authentication types (bit field of WPS_AUTH_*) + */ + u16 auth_types; + + /** + * network_key - The current Network Key (PSK) or %NULL to generate new + * + * If %NULL, Registrar will generate per-device PSK. In addition, AP + * uses this when acting as an Enrollee to notify Registrar of the + * current configuration. + * + * When using WPA/WPA2-Person, this key can be either the ASCII + * passphrase (8..63 characters) or the 32-octet PSK (64 hex + * characters). When this is set to the ASCII passphrase, the PSK can + * be provided in the psk buffer and used per-Enrollee to control which + * key type is included in the Credential (e.g., to reduce calculation + * need on low-powered devices by provisioning PSK while still allowing + * other devices to get the passphrase). + */ + u8 *network_key; + + /** + * network_key_len - Length of network_key in octets + */ + size_t network_key_len; + + /** + * psk - The current network PSK + * + * This optional value can be used to provide the current PSK if + * network_key is set to the ASCII passphrase. + */ + u8 psk[32]; + + /** + * psk_set - Whether psk value is set + */ + int psk_set; + + /** + * ap_settings - AP Settings override for M7 (only used at AP) + * + * If %NULL, AP Settings attributes will be generated based on the + * current network configuration. + */ + u8 *ap_settings; + + /** + * ap_settings_len - Length of ap_settings in octets + */ + size_t ap_settings_len; + + /** + * friendly_name - Friendly Name (required for UPnP) + */ + char *friendly_name; + + /** + * manufacturer_url - Manufacturer URL (optional for UPnP) + */ + char *manufacturer_url; + + /** + * model_description - Model Description (recommended for UPnP) + */ + char *model_description; + + /** + * model_url - Model URL (optional for UPnP) + */ + char *model_url; + + /** + * upc - Universal Product Code (optional for UPnP) + */ + char *upc; + + /** + * cred_cb - Callback to notify that new Credentials were received + * @ctx: Higher layer context data (cb_ctx) + * @cred: The received Credential + * Return: 0 on success, -1 on failure + */ + int (*cred_cb)(void *ctx, const struct wps_credential *cred); + + /** + * event_cb - Event callback (state information about progress) + * @ctx: Higher layer context data (cb_ctx) + * @event: Event type + * @data: Event data + */ + void (*event_cb)(void *ctx, enum wps_event event, + union wps_event_data *data); + + /** + * cb_ctx: Higher layer context data for callbacks + */ + void *cb_ctx; + + //struct upnp_wps_device_sm *wps_upnp; + + /* Pending messages from UPnP PutWLANResponse */ + //struct upnp_pending_message *upnp_msgs; +#ifdef CONFIG_WPS_NFC + + u16 ap_nfc_dev_pw_id; + struct wpabuf *ap_nfc_dh_pubkey; + struct wpabuf *ap_nfc_dh_privkey; + struct wpabuf *ap_nfc_dev_pw; +#endif +}; + +struct wps_registrar * +wps_registrar_init(struct wps_context *wps, + const struct wps_registrar_config *cfg); +void wps_registrar_deinit(struct wps_registrar *reg); +#ifdef CONFIG_WPS_PIN + +int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr, + const u8 *uuid, const u8 *pin, size_t pin_len, + int timeout); +int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid); +int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid); +#endif +int wps_registrar_wps_cancel(struct wps_registrar *reg); + +int wps_registrar_button_pushed(struct wps_registrar *reg, + const u8 *p2p_dev_addr); +void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e, + const u8 *dev_pw, size_t dev_pw_len); +void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, + const struct wpabuf *wps_data, + int p2p_wildcard); +int wps_registrar_update_ie(struct wps_registrar *reg); +int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr, + char *buf, size_t buflen); +int wps_registrar_config_ap(struct wps_registrar *reg, + struct wps_credential *cred); +#ifdef CONFIG_WPS_NFC + +int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg, + const u8 *pubkey_hash, u16 pw_id, + const u8 *dev_pw, size_t dev_pw_len); +int wps_registrar_add_nfc_password_token(struct wps_registrar *reg, + const u8 *oob_dev_pw, + size_t oob_dev_pw_len); +#endif +int wps_build_credential_wrap(struct wpabuf *msg, + const struct wps_credential *cred); +#ifdef CONFIG_WPS_PIN + +unsigned int wps_pin_checksum(unsigned int pin); +unsigned int wps_pin_valid(unsigned int pin); +unsigned int wps_generate_pin(void); +int wps_pin_str_valid(const char *pin); +#endif + +#ifdef CONFIG_WPS_OOB + +struct wpabuf * wps_get_oob_cred(struct wps_context *wps); +int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr); +#endif +int wps_attr_text(struct wpabuf *data, char *buf, char *end); + +struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname, + const char *filter); +void wps_er_refresh(struct wps_er *er); +void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx); +void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id, + u16 sel_reg_config_methods); +int wps_er_pbc(struct wps_er *er, const u8 *uuid); +int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin, + size_t pin_len); +int wps_er_set_config(struct wps_er *er, const u8 *uuid, + const struct wps_credential *cred); +int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin, + size_t pin_len, const struct wps_credential *cred); +#ifdef CONFIG_WPS_NFC + +struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid); + +#endif + +int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]); +char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf, + size_t buf_len); +void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid); +u16 wps_config_methods_str2bin(const char *str); + +#ifdef CONFIG_WPS_NFC + +struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id, + const struct wpabuf *pubkey, + const struct wpabuf *dev_pw); +struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey, + struct wpabuf **privkey, + struct wpabuf **dev_pw); +#endif + +/* ndef.c */ +struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf); +struct wpabuf * ndef_build_wifi(const struct wpabuf *buf); +struct wpabuf * ndef_build_wifi_hr(void); + +#ifdef CONFIG_WPS_STRICT +int wps_validate_beacon(const struct wpabuf *wps_ie); +int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, int probe, + const u8 *addr); +int wps_validate_probe_req(const struct wpabuf *wps_ie, const u8 *addr); +int wps_validate_assoc_req(const struct wpabuf *wps_ie); +int wps_validate_assoc_resp(const struct wpabuf *wps_ie); +int wps_validate_m1(const struct wpabuf *tlvs); +int wps_validate_m2(const struct wpabuf *tlvs); +int wps_validate_m2d(const struct wpabuf *tlvs); +int wps_validate_m3(const struct wpabuf *tlvs); +int wps_validate_m4(const struct wpabuf *tlvs); +int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2); +int wps_validate_m5(const struct wpabuf *tlvs); +int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2); +int wps_validate_m6(const struct wpabuf *tlvs); +int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2); +int wps_validate_m7(const struct wpabuf *tlvs); +int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap, int wps2); +int wps_validate_m8(const struct wpabuf *tlvs); +int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap, int wps2); +int wps_validate_wsc_ack(const struct wpabuf *tlvs); +int wps_validate_wsc_nack(const struct wpabuf *tlvs); +int wps_validate_wsc_done(const struct wpabuf *tlvs); +int wps_validate_upnp_set_selected_registrar(const struct wpabuf *tlvs); +#else /* CONFIG_WPS_STRICT */ +static inline int wps_validate_beacon(const struct wpabuf *wps_ie){ + return 0; +} + +static inline int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, + int probe, const u8 *addr) +{ + return 0; +} + +static inline int wps_validate_probe_req(const struct wpabuf *wps_ie, + const u8 *addr) +{ + return 0; +} + +static inline int wps_validate_assoc_req(const struct wpabuf *wps_ie) +{ + return 0; +} + +static inline int wps_validate_assoc_resp(const struct wpabuf *wps_ie) +{ + return 0; +} + +static inline int wps_validate_m1(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_m2(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_m2d(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_m3(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_m4(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2) +{ + return 0; +} + +static inline int wps_validate_m5(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2) +{ + return 0; +} + +static inline int wps_validate_m6(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2) +{ + return 0; +} + +static inline int wps_validate_m7(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap, + int wps2) +{ + return 0; +} + +static inline int wps_validate_m8(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap, + int wps2) +{ + return 0; +} + +static inline int wps_validate_wsc_ack(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_wsc_nack(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_wsc_done(const struct wpabuf *tlvs) +{ + return 0; +} + +static inline int wps_validate_upnp_set_selected_registrar( + const struct wpabuf *tlvs) +{ + return 0; +} +#endif /* CONFIG_WPS_STRICT */ + +enum wps_cb_status { + WPS_CB_ST_SUCCESS = 0, + WPS_CB_ST_FAILED, + WPS_CB_ST_TIMEOUT, + WPS_CB_ST_WEP, + WPS_CB_ST_SCAN_ERR, +}; + +typedef void (*wps_st_cb_t)(int status); + +#if 1//def USE_WPS_TASK +#define SIG_WPS_START 0 +#define SIG_WPS_RX 1 +#define SIG_WPS_NUM 2 +#endif + +#define WPS_EAP_EXT_VENDOR_TYPE "WFA-SimpleConfig-Enrollee-1-0" +#define WPS_OUTBUF_SIZE 500 +struct wps_sm { + struct wps_config *wps_cfg; + struct wps_context *wps_ctx; + struct wps_data *wps; + char identity[32]; + u8 identity_len; + u8 ownaddr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 ssid[32]; + u8 ssid_len; + struct wps_device_data *dev; + u8 uuid[16]; + u8 eapol_version; + char key[64]; + u8 key_len; + //uint8_t *outbuf; + //uint16_t outbuflen; + os_timer_t wps_timeout_timer; + os_timer_t wps_msg_timeout_timer; + os_timer_t wps_scan_timer; + os_timer_t wps_success_cb_timer; + os_timer_t wps_eapol_start_timer; + wps_st_cb_t st_cb; + u8 current_identifier; + bool is_wps_scan; + u8 channel; + u8 scan_cnt; +#if 1//def USE_WPS_TASK + u8 wps_sig_cnt[SIG_WPS_NUM]; +#endif + u8 discover_ssid_cnt; + bool ignore_sel_reg; + struct discard_ap_list_t dis_ap_list[WPS_MAX_DIS_AP_NUM]; + u8 discard_ap_cnt; + wifi_sta_config_t config; +}; + +struct wps_sm *wps_sm_get(void); +int wps_ssid_save(u8 *ssid, u8 ssid_len); +int wps_key_save(char *key, u8 key_len); +int wps_station_wps_register_cb(wps_st_cb_t cb); +int wps_station_wps_unregister_cb(void); +int wps_start_pending(void); +int wps_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); + +int wps_dev_deinit(struct wps_device_data *dev); +#endif /* WPS_H */ diff --git a/components/wpa_supplicant/include/wps/wps_attr_parse.h b/components/wpa_supplicant/include/wps/wps_attr_parse.h new file mode 100644 index 00000000..86061aea --- /dev/null +++ b/components/wpa_supplicant/include/wps/wps_attr_parse.h @@ -0,0 +1,108 @@ +/* + * Wi-Fi Protected Setup - attribute parsing + * 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_ATTR_PARSE_H +#define WPS_ATTR_PARSE_H + +#include "wps/wps.h" + +struct wps_parse_attr { + /* fixed length fields */ + const u8 *version; /* 1 octet */ + const u8 *version2; /* 1 octet */ + const u8 *msg_type; /* 1 octet */ + const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */ + const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */ + const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */ + const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */ + const u8 *auth_type_flags; /* 2 octets */ + const u8 *encr_type_flags; /* 2 octets */ + const u8 *conn_type_flags; /* 1 octet */ + const u8 *config_methods; /* 2 octets */ + const u8 *sel_reg_config_methods; /* 2 octets */ + const u8 *primary_dev_type; /* 8 octets */ + const u8 *rf_bands; /* 1 octet */ + const u8 *assoc_state; /* 2 octets */ + const u8 *config_error; /* 2 octets */ + const u8 *dev_password_id; /* 2 octets */ + const u8 *os_version; /* 4 octets */ + const u8 *wps_state; /* 1 octet */ + const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */ + const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */ + const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */ + const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */ + const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */ + const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */ + const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */ + const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */ + const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */ + const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */ + const u8 *auth_type; /* 2 octets */ + const u8 *encr_type; /* 2 octets */ + const u8 *network_idx; /* 1 octet */ + const u8 *network_key_idx; /* 1 octet */ + const u8 *mac_addr; /* ETH_ALEN (6) octets */ + const u8 *key_prov_auto; /* 1 octet (Bool) */ + const u8 *dot1x_enabled; /* 1 octet (Bool) */ + const u8 *selected_registrar; /* 1 octet (Bool) */ + const u8 *request_type; /* 1 octet */ + const u8 *response_type; /* 1 octet */ + const u8 *ap_setup_locked; /* 1 octet */ + const u8 *settings_delay_time; /* 1 octet */ + const u8 *network_key_shareable; /* 1 octet (Bool) */ + const u8 *request_to_enroll; /* 1 octet (Bool) */ + const u8 *ap_channel; /* 2 octets */ + + /* variable length fields */ + const u8 *manufacturer; + size_t manufacturer_len; + const u8 *model_name; + size_t model_name_len; + const u8 *model_number; + size_t model_number_len; + const u8 *serial_number; + size_t serial_number_len; + const u8 *dev_name; + size_t dev_name_len; + const u8 *public_key; + size_t public_key_len; + const u8 *encr_settings; + size_t encr_settings_len; + const u8 *ssid; /* <= 32 octets */ + size_t ssid_len; + const u8 *network_key; /* <= 64 octets */ + size_t network_key_len; + const u8 *eap_type; /* <= 8 octets */ + size_t eap_type_len; + const u8 *eap_identity; /* <= 64 octets */ + size_t eap_identity_len; + const u8 *authorized_macs; /* <= 30 octets */ + size_t authorized_macs_len; + const u8 *sec_dev_type_list; /* <= 128 octets */ + size_t sec_dev_type_list_len; + const u8 *oob_dev_password; /* 38..54 octets */ + size_t oob_dev_password_len; + + /* attributes that can occur multiple times */ +#define MAX_CRED_COUNT 10 + const u8 *cred[MAX_CRED_COUNT]; + size_t cred_len[MAX_CRED_COUNT]; + size_t num_cred; + +#define MAX_REQ_DEV_TYPE_COUNT 10 + const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT]; + size_t num_req_dev_type; + + const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT]; + size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT]; + size_t num_vendor_ext; +}; + +int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr); + +#endif /* WPS_ATTR_PARSE_H */ diff --git a/components/wpa_supplicant/include/wps/wps_defs.h b/components/wpa_supplicant/include/wps/wps_defs.h new file mode 100644 index 00000000..9c047588 --- /dev/null +++ b/components/wpa_supplicant/include/wps/wps_defs.h @@ -0,0 +1,341 @@ +/* + * Wi-Fi Protected Setup - message definitions + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPS_DEFS_H +#define WPS_DEFS_H + +#ifdef CONFIG_WPS_TESTING + +extern int wps_version_number; +extern int wps_testing_dummy_cred; +#define WPS_VERSION wps_version_number + +#else /* CONFIG_WPS_TESTING */ + +#ifdef CONFIG_WPS2 +#define WPS_VERSION 0x20 +#else /* CONFIG_WPS2 */ +#define WPS_VERSION 0x10 +#endif /* CONFIG_WPS2 */ + +#endif /* CONFIG_WPS_TESTING */ + +#define CONFIG_WPS_STRICT + +/* Diffie-Hellman 1536-bit MODP Group; RFC 3526, Group 5 */ +#define WPS_DH_GROUP 5 + +#define WPS_UUID_LEN 16 +#define WPS_NONCE_LEN 16 +#define WPS_AUTHENTICATOR_LEN 8 +#define WPS_AUTHKEY_LEN 32 +#define WPS_KEYWRAPKEY_LEN 16 +#define WPS_EMSK_LEN 32 +#define WPS_PSK_LEN 16 +#define WPS_SECRET_NONCE_LEN 16 +#define WPS_HASH_LEN 32 +#define WPS_KWA_LEN 8 +#define WPS_MGMTAUTHKEY_LEN 32 +#define WPS_MGMTENCKEY_LEN 16 +#define WPS_MGMT_KEY_ID_LEN 16 +#define WPS_OOB_DEVICE_PASSWORD_MIN_LEN 16 +#define WPS_OOB_DEVICE_PASSWORD_LEN 32 +#define WPS_OOB_PUBKEY_HASH_LEN 20 + +/* Attribute Types */ +enum wps_attribute { + ATTR_AP_CHANNEL = 0x1001, + ATTR_ASSOC_STATE = 0x1002, + ATTR_AUTH_TYPE = 0x1003, + ATTR_AUTH_TYPE_FLAGS = 0x1004, + ATTR_AUTHENTICATOR = 0x1005, + ATTR_CONFIG_METHODS = 0x1008, + ATTR_CONFIG_ERROR = 0x1009, + ATTR_CONFIRM_URL4 = 0x100a, + ATTR_CONFIRM_URL6 = 0x100b, + ATTR_CONN_TYPE = 0x100c, + ATTR_CONN_TYPE_FLAGS = 0x100d, + ATTR_CRED = 0x100e, + ATTR_ENCR_TYPE = 0x100f, + ATTR_ENCR_TYPE_FLAGS = 0x1010, + ATTR_DEV_NAME = 0x1011, + ATTR_DEV_PASSWORD_ID = 0x1012, + ATTR_E_HASH1 = 0x1014, + ATTR_E_HASH2 = 0x1015, + ATTR_E_SNONCE1 = 0x1016, + ATTR_E_SNONCE2 = 0x1017, + ATTR_ENCR_SETTINGS = 0x1018, + ATTR_ENROLLEE_NONCE = 0x101a, + ATTR_FEATURE_ID = 0x101b, + ATTR_IDENTITY = 0x101c, + ATTR_IDENTITY_PROOF = 0x101d, + ATTR_KEY_WRAP_AUTH = 0x101e, + ATTR_KEY_ID = 0x101f, + ATTR_MAC_ADDR = 0x1020, + ATTR_MANUFACTURER = 0x1021, + ATTR_MSG_TYPE = 0x1022, + ATTR_MODEL_NAME = 0x1023, + ATTR_MODEL_NUMBER = 0x1024, + ATTR_NETWORK_INDEX = 0x1026, + ATTR_NETWORK_KEY = 0x1027, + ATTR_NETWORK_KEY_INDEX = 0x1028, + ATTR_NEW_DEVICE_NAME = 0x1029, + ATTR_NEW_PASSWORD = 0x102a, + ATTR_OOB_DEVICE_PASSWORD = 0x102c, + ATTR_OS_VERSION = 0x102d, + ATTR_POWER_LEVEL = 0x102f, + ATTR_PSK_CURRENT = 0x1030, + ATTR_PSK_MAX = 0x1031, + ATTR_PUBLIC_KEY = 0x1032, + ATTR_RADIO_ENABLE = 0x1033, + ATTR_REBOOT = 0x1034, + ATTR_REGISTRAR_CURRENT = 0x1035, + ATTR_REGISTRAR_ESTABLISHED = 0x1036, + ATTR_REGISTRAR_LIST = 0x1037, + ATTR_REGISTRAR_MAX = 0x1038, + ATTR_REGISTRAR_NONCE = 0x1039, + ATTR_REQUEST_TYPE = 0x103a, + ATTR_RESPONSE_TYPE = 0x103b, + ATTR_RF_BANDS = 0x103c, + ATTR_R_HASH1 = 0x103d, + ATTR_R_HASH2 = 0x103e, + ATTR_R_SNONCE1 = 0x103f, + ATTR_R_SNONCE2 = 0x1040, + ATTR_SELECTED_REGISTRAR = 0x1041, + ATTR_SERIAL_NUMBER = 0x1042, + ATTR_WPS_STATE = 0x1044, + ATTR_SSID = 0x1045, + ATTR_TOTAL_NETWORKS = 0x1046, + ATTR_UUID_E = 0x1047, + ATTR_UUID_R = 0x1048, + ATTR_VENDOR_EXT = 0x1049, + ATTR_VERSION = 0x104a, + ATTR_X509_CERT_REQ = 0x104b, + ATTR_X509_CERT = 0x104c, + ATTR_EAP_IDENTITY = 0x104d, + ATTR_MSG_COUNTER = 0x104e, + ATTR_PUBKEY_HASH = 0x104f, + ATTR_REKEY_KEY = 0x1050, + ATTR_KEY_LIFETIME = 0x1051, + ATTR_PERMITTED_CFG_METHODS = 0x1052, + ATTR_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053, + ATTR_PRIMARY_DEV_TYPE = 0x1054, + ATTR_SECONDARY_DEV_TYPE_LIST = 0x1055, + ATTR_PORTABLE_DEV = 0x1056, + ATTR_AP_SETUP_LOCKED = 0x1057, + ATTR_APPLICATION_EXT = 0x1058, + ATTR_EAP_TYPE = 0x1059, + ATTR_IV = 0x1060, + ATTR_KEY_PROVIDED_AUTO = 0x1061, + ATTR_802_1X_ENABLED = 0x1062, + ATTR_APPSESSIONKEY = 0x1063, + ATTR_WEPTRANSMITKEY = 0x1064, + ATTR_REQUESTED_DEV_TYPE = 0x106a, + ATTR_EXTENSIBILITY_TEST = 0x10fa /* _NOT_ defined in the spec */ +}; + +#define WPS_VENDOR_ID_WFA 14122 + +/* WFA Vendor Extension subelements */ +enum { + WFA_ELEM_VERSION2 = 0x00, + WFA_ELEM_AUTHORIZEDMACS = 0x01, + WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02, + WFA_ELEM_REQUEST_TO_ENROLL = 0x03, + WFA_ELEM_SETTINGS_DELAY_TIME = 0x04 +}; + +/* Device Password ID */ +enum wps_dev_password_id { + DEV_PW_DEFAULT = 0x0000, + DEV_PW_USER_SPECIFIED = 0x0001, + DEV_PW_MACHINE_SPECIFIED = 0x0002, + DEV_PW_REKEY = 0x0003, + DEV_PW_PUSHBUTTON = 0x0004, + DEV_PW_REGISTRAR_SPECIFIED = 0x0005 +}; + +/* WPS message flag */ +enum wps_msg_flag { + WPS_MSG_FLAG_MORE = 0x01, + WPS_MSG_FLAG_LEN = 0x02 +}; + +/* Message Type */ +enum wps_msg_type { + WPS_Beacon = 0x01, + WPS_ProbeRequest = 0x02, + WPS_ProbeResponse = 0x03, + WPS_M1 = 0x04, + WPS_M2 = 0x05, + WPS_M2D = 0x06, + WPS_M3 = 0x07, + WPS_M4 = 0x08, + WPS_M5 = 0x09, + WPS_M6 = 0x0a, + WPS_M7 = 0x0b, + WPS_M8 = 0x0c, + WPS_WSC_ACK = 0x0d, + WPS_WSC_NACK = 0x0e, + WPS_WSC_DONE = 0x0f +}; + +/* Authentication Type Flags */ +#define WPS_AUTH_OPEN 0x0001 +#define WPS_AUTH_WPAPSK 0x0002 +#define WPS_AUTH_SHARED 0x0004 +#define WPS_AUTH_WPA 0x0008 +#define WPS_AUTH_WPA2 0x0010 +#define WPS_AUTH_WPA2PSK 0x0020 +#define WPS_AUTH_TYPES (WPS_AUTH_OPEN | WPS_AUTH_WPAPSK | WPS_AUTH_SHARED | \ + WPS_AUTH_WPA | WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK) + +/* Encryption Type Flags */ +#define WPS_ENCR_NONE 0x0001 +#define WPS_ENCR_WEP 0x0002 +#define WPS_ENCR_TKIP 0x0004 +#define WPS_ENCR_AES 0x0008 +#define WPS_ENCR_TYPES (WPS_ENCR_NONE | WPS_ENCR_WEP | WPS_ENCR_TKIP | \ + WPS_ENCR_AES) + +/* Configuration Error */ +enum wps_config_error { + WPS_CFG_NO_ERROR = 0, + WPS_CFG_OOB_IFACE_READ_ERROR = 1, + WPS_CFG_DECRYPTION_CRC_FAILURE = 2, + WPS_CFG_24_CHAN_NOT_SUPPORTED = 3, + WPS_CFG_50_CHAN_NOT_SUPPORTED = 4, + WPS_CFG_SIGNAL_TOO_WEAK = 5, + WPS_CFG_NETWORK_AUTH_FAILURE = 6, + WPS_CFG_NETWORK_ASSOC_FAILURE = 7, + WPS_CFG_NO_DHCP_RESPONSE = 8, + WPS_CFG_FAILED_DHCP_CONFIG = 9, + WPS_CFG_IP_ADDR_CONFLICT = 10, + WPS_CFG_NO_CONN_TO_REGISTRAR = 11, + WPS_CFG_MULTIPLE_PBC_DETECTED = 12, + WPS_CFG_ROGUE_SUSPECTED = 13, + WPS_CFG_DEVICE_BUSY = 14, + WPS_CFG_SETUP_LOCKED = 15, + WPS_CFG_MSG_TIMEOUT = 16, + WPS_CFG_REG_SESS_TIMEOUT = 17, + WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18 +}; + +/* Vendor specific Error Indication for WPS event messages */ +enum wps_error_indication { + WPS_EI_NO_ERROR, + WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED, + WPS_EI_SECURITY_WEP_PROHIBITED, + NUM_WPS_EI_VALUES +}; + +/* RF Bands */ +#define WPS_RF_24GHZ 0x01 +#define WPS_RF_50GHZ 0x02 + +/* Config Methods */ +#define WPS_CONFIG_USBA 0x0001 +#define WPS_CONFIG_ETHERNET 0x0002 +#define WPS_CONFIG_LABEL 0x0004 +#define WPS_CONFIG_DISPLAY 0x0008 +#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010 +#define WPS_CONFIG_INT_NFC_TOKEN 0x0020 +#define WPS_CONFIG_NFC_INTERFACE 0x0040 +#define WPS_CONFIG_PUSHBUTTON 0x0080 +#define WPS_CONFIG_KEYPAD 0x0100 +#ifdef CONFIG_WPS2 +#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280 +#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480 +#define WPS_CONFIG_VIRT_DISPLAY 0x2008 +#define WPS_CONFIG_PHY_DISPLAY 0x4008 +#endif /* CONFIG_WPS2 */ + +/* Connection Type Flags */ +#define WPS_CONN_ESS 0x01 +#define WPS_CONN_IBSS 0x02 + +/* Wi-Fi Protected Setup State */ +enum wps_state { + WPS_STATE_NOT_CONFIGURED = 1, + WPS_STATE_CONFIGURED = 2 +}; + +/* Association State */ +enum wps_assoc_state { + WPS_ASSOC_NOT_ASSOC = 0, + WPS_ASSOC_CONN_SUCCESS = 1, + WPS_ASSOC_CFG_FAILURE = 2, + WPS_ASSOC_FAILURE = 3, + WPS_ASSOC_IP_FAILURE = 4 +}; + + +#define WPS_DEV_OUI_WFA 0x0050f204 + +enum wps_dev_categ { + WPS_DEV_COMPUTER = 1, + WPS_DEV_INPUT = 2, + WPS_DEV_PRINTER = 3, + WPS_DEV_CAMERA = 4, + WPS_DEV_STORAGE = 5, + WPS_DEV_NETWORK_INFRA = 6, + WPS_DEV_DISPLAY = 7, + WPS_DEV_MULTIMEDIA = 8, + WPS_DEV_GAMING = 9, + WPS_DEV_PHONE = 10 +}; + +enum wps_dev_subcateg { + WPS_DEV_COMPUTER_PC = 1, + WPS_DEV_COMPUTER_SERVER = 2, + WPS_DEV_COMPUTER_MEDIA_CENTER = 3, + WPS_DEV_PRINTER_PRINTER = 1, + WPS_DEV_PRINTER_SCANNER = 2, + WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1, + WPS_DEV_STORAGE_NAS = 1, + WPS_DEV_NETWORK_INFRA_AP = 1, + WPS_DEV_NETWORK_INFRA_ROUTER = 2, + WPS_DEV_NETWORK_INFRA_SWITCH = 3, + WPS_DEV_DISPLAY_TV = 1, + WPS_DEV_DISPLAY_PICTURE_FRAME = 2, + WPS_DEV_DISPLAY_PROJECTOR = 3, + WPS_DEV_MULTIMEDIA_DAR = 1, + WPS_DEV_MULTIMEDIA_PVR = 2, + WPS_DEV_MULTIMEDIA_MCX = 3, + WPS_DEV_GAMING_XBOX = 1, + WPS_DEV_GAMING_XBOX360 = 2, + WPS_DEV_GAMING_PLAYSTATION = 3, + WPS_DEV_PHONE_WINDOWS_MOBILE = 1 +}; + + +/* Request Type */ +enum wps_request_type { + WPS_REQ_ENROLLEE_INFO = 0, + WPS_REQ_ENROLLEE = 1, + WPS_REQ_REGISTRAR = 2, + WPS_REQ_WLAN_MANAGER_REGISTRAR = 3 +}; + +/* Response Type */ +enum wps_response_type { + WPS_RESP_ENROLLEE_INFO = 0, + WPS_RESP_ENROLLEE = 1, + WPS_RESP_REGISTRAR = 2, + WPS_RESP_AP = 3 +}; + +/* Walk Time for push button configuration (in seconds) */ +#define WPS_PBC_WALK_TIME 120 + +#define WPS_MAX_AUTHORIZED_MACS 5 + +#define WPS_IGNORE_SEL_REG_MAX_CNT 4 + +#define WPS_MAX_DIS_AP_NUM 10 +#endif /* WPS_DEFS_H */ diff --git a/components/wpa_supplicant/include/wps/wps_dev_attr.h b/components/wpa_supplicant/include/wps/wps_dev_attr.h new file mode 100644 index 00000000..200c9c45 --- /dev/null +++ b/components/wpa_supplicant/include/wps/wps_dev_attr.h @@ -0,0 +1,39 @@ +/* + * Wi-Fi Protected Setup - device attributes + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPS_DEV_ATTR_H +#define WPS_DEV_ATTR_H + +struct wps_parse_attr; + +int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_primary_dev_type(struct wps_device_data *dev, + struct wpabuf *msg); +int wps_build_secondary_dev_type(struct wps_device_data *dev, + struct wpabuf *msg); +int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg); +int wps_process_device_attrs(struct wps_device_data *dev, + struct wps_parse_attr *attr); +int wps_process_os_version(struct wps_device_data *dev, const u8 *ver); +int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands); +void wps_device_data_dup(struct wps_device_data *dst, + const struct wps_device_data *src); +void wps_device_data_free(struct wps_device_data *dev); +int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg, + unsigned int num_req_dev_types, + const u8 *req_dev_types); + +#endif /* WPS_DEV_ATTR_H */ diff --git a/components/wpa_supplicant/include/wps/wps_i.h b/components/wpa_supplicant/include/wps/wps_i.h new file mode 100644 index 00000000..70a673a3 --- /dev/null +++ b/components/wpa_supplicant/include/wps/wps_i.h @@ -0,0 +1,244 @@ +/* + * Wi-Fi Protected Setup - internal definitions + * 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_I_H +#define WPS_I_H + +#include "wps/wps.h" +#include "wps/wps_attr_parse.h" + +#ifdef CONFIG_WPS_NFC +struct wps_nfc_pw_token; +#endif +/** + * struct wps_data - WPS registration protocol data + * + * This data is stored at the EAP-WSC server/peer method and it is kept for a + * single registration protocol run. + */ +struct wps_data { + /** + * wps - Pointer to long term WPS context + */ + struct wps_context *wps; + + /** + * registrar - Whether this end is a Registrar + */ + int registrar; + + /** + * er - Whether the local end is an external registrar + */ + int er; + + enum { + /* Enrollee states */ + SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7, + RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED, + SEND_WSC_NACK, + + /* Registrar states */ + RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6, + RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK + } state; + + u8 uuid_e[WPS_UUID_LEN]; + u8 uuid_r[WPS_UUID_LEN]; + u8 mac_addr_e[ETH_ALEN]; + u8 nonce_e[WPS_NONCE_LEN]; + u8 nonce_r[WPS_NONCE_LEN]; + u8 psk1[WPS_PSK_LEN]; + u8 psk2[WPS_PSK_LEN]; + u8 snonce[2 * WPS_SECRET_NONCE_LEN]; + u8 peer_hash1[WPS_HASH_LEN]; + u8 peer_hash2[WPS_HASH_LEN]; + + struct wpabuf *dh_privkey; + struct wpabuf *dh_pubkey_e; + struct wpabuf *dh_pubkey_r; + u8 authkey[WPS_AUTHKEY_LEN]; + u8 keywrapkey[WPS_KEYWRAPKEY_LEN]; + u8 emsk[WPS_EMSK_LEN]; + + struct wpabuf *last_msg; + + u8 *dev_password; + size_t dev_password_len; + u16 dev_pw_id; + int pbc; + + /** + * request_type - Request Type attribute from (Re)AssocReq + */ + u8 request_type; + + /** + * encr_type - Available encryption types + */ + u16 encr_type; + + /** + * auth_type - Available authentication types + */ + u16 auth_type; + + u8 *new_psk; + size_t new_psk_len; + + int wps_pin_revealed; + struct wps_credential cred; + + struct wps_device_data peer_dev; + + /** + * config_error - Configuration Error value to be used in NACK + */ + u16 config_error; + u16 error_indication; + + int ext_reg; + int int_reg; + + struct wps_credential *new_ap_settings; + + void *dh_ctx; + + void (*ap_settings_cb)(void *ctx, const struct wps_credential *cred); + void *ap_settings_cb_ctx; + + struct wps_credential *use_cred; + + int use_psk_key; + u8 p2p_dev_addr[ETH_ALEN]; /* P2P Device Address of the client or + * 00:00:00:00:00:00 if not a P2p client */ + int pbc_in_m1; +#ifdef CONFIG_WPS_NFC + struct wps_nfc_pw_token *nfc_pw_token; +#endif +}; + +typedef enum wps_type { + WPS_TYPE_DISABLE = 0, + WPS_TYPE_E_PBC, + WPS_TYPE_E_PIN, + WPS_TYPE_E_DISPLAY, + WPS_TYPE_E_MAX, + WPS_TYPE_R_PBC, + WPS_TYPE_R_PIN, + WPS_TYPE_R_DISPLAY, + WPS_TYPE_R_MAX, + WPS_TYPE_ALL_MAX, +} WPS_TYPE_t; + +#define WPS_MAX_MANUFACTURER_LEN 65 +#define WPS_MAX_MODEL_NUMBER_LEN 33 +#define WPS_MAX_MODEL_NAME_LEN 33 +#define WPS_MAX_DEV_NAME_LEN 33 +typedef struct { + char manufacturer[WPS_MAX_MANUFACTURER_LEN]; + char model_number[WPS_MAX_MODEL_NUMBER_LEN]; + char model_name[WPS_MAX_MODEL_NAME_LEN]; + char device_name[WPS_MAX_DEV_NAME_LEN]; +} esp_factory_information_t; + +typedef struct { + WPS_TYPE_t wps_type; + esp_factory_information_t factory_info; +}esp_wps_config_t; + + +/* wps_common.c */ +void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, + const char *label, u8 *res, size_t res_len); +int wps_derive_keys(struct wps_data *wps); +void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, + size_t dev_passwd_len); +struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, + size_t encr_len); +void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg, + u16 config_error, u16 error_indication); +void wps_success_event(struct wps_context *wps); +void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part); +void wps_pbc_overlap_event(struct wps_context *wps); +void wps_pbc_timeout_event(struct wps_context *wps); + +struct wpabuf * wps_build_wsc_ack(struct wps_data *wps); +struct wpabuf * wps_build_wsc_nack(struct wps_data *wps); + +typedef enum wps_calc_key_mode { + WPS_CALC_KEY_NORMAL = 0, + WPS_CALC_KEY_NO_CALC, + WPS_CALC_KEY_PRE_CALC, + WPS_CALC_KEY_MAX, +} wps_key_mode_t; + +/* wps_attr_build.c */ +int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg, wps_key_mode_t mode); +int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type); +int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type); +int wps_build_config_methods(struct wpabuf *msg, u16 methods); +int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid); +int wps_build_dev_password_id(struct wpabuf *msg, u16 id); +int wps_build_config_error(struct wpabuf *msg, u16 err); +int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg); +int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg); +int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg, + struct wpabuf *plain); +int wps_build_version(struct wpabuf *msg); +int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, + const u8 *auth_macs, size_t auth_macs_count); +int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type); +int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg); +int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg); +int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg); +int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg); +int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg); +int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg); +int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id, + const struct wpabuf *pubkey, const u8 *dev_pw, + size_t dev_pw_len); +struct wpabuf * wps_ie_encapsulate(struct wpabuf *data); + +/* wps_attr_process.c */ +int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator, + const struct wpabuf *msg); +int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg, + const u8 *key_wrap_auth); +int wps_process_cred(struct wps_parse_attr *attr, + struct wps_credential *cred); +int wps_process_ap_settings(struct wps_parse_attr *attr, + struct wps_credential *cred); + +/* wps_enrollee.c */ +struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps, + enum wsc_op_code *op_code); +enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps, + enum wsc_op_code op_code, + const struct wpabuf *msg); + +/* wps_registrar.c */ +struct wpabuf * wps_registrar_get_msg(struct wps_data *wps, + enum wsc_op_code *op_code); +enum wps_process_res wps_registrar_process_msg(struct wps_data *wps, + enum wsc_op_code op_code, + const struct wpabuf *msg); +int wps_build_cred(struct wps_data *wps, struct wpabuf *msg); +int wps_device_store(struct wps_registrar *reg, + struct wps_device_data *dev, const u8 *uuid); +void wps_registrar_selected_registrar_changed(struct wps_registrar *reg); +const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count); +int wps_registrar_pbc_overlap(struct wps_registrar *reg, + const u8 *addr, const u8 *uuid_e); +#ifdef CONFIG_WPS_NFC + +void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg, + struct wps_nfc_pw_token *token); +#endif + +#endif /* WPS_I_H */ diff --git a/components/wpa_supplicant/src/wps/eap_common.c b/components/wpa_supplicant/src/wps/eap_common.c new file mode 100755 index 00000000..d2dbdc08 --- /dev/null +++ b/components/wpa_supplicant/src/wps/eap_common.c @@ -0,0 +1,218 @@ +/* + * EAP common peer/server definitions + * Copyright (c) 2004-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "wpa/includes.h" +#include "wpa/common.h" +#include "eap/eap_defs.h" +#include "eap/eap_common.h" + +/** + * eap_hdr_len_valid - Validate EAP header length field + * @msg: EAP frame (starting with EAP header) + * @min_payload: Minimum payload length needed + * Returns: 1 for valid header, 0 for invalid + * + * This is a helper function that does minimal validation of EAP messages. The + * length field is verified to be large enough to include the header and not + * too large to go beyond the end of the buffer. + */ +int ICACHE_FLASH_ATTR eap_hdr_len_valid(const struct wpabuf* msg, size_t min_payload) +{ + const struct eap_hdr* hdr; + size_t len; + + if (msg == NULL) { + return 0; + } + + hdr = wpabuf_head(msg); + + if (wpabuf_len(msg) < sizeof(*hdr)) { + wpa_printf(MSG_INFO, "EAP: Too short EAP frame"); + return 0; + } + + len = be_to_host16(hdr->length); + + if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) { + wpa_printf(MSG_INFO, "EAP: Invalid EAP length"); + return 0; + } + + return 1; +} + + +/** + * eap_hdr_validate - Validate EAP header + * @vendor: Expected EAP Vendor-Id (0 = IETF) + * @eap_type: Expected EAP type number + * @msg: EAP frame (starting with EAP header) + * @plen: Pointer to variable to contain the returned payload length + * Returns: Pointer to EAP payload (after type field), or %NULL on failure + * + * This is a helper function for EAP method implementations. This is usually + * called in the beginning of struct eap_method::process() function to verify + * that the received EAP request packet has a valid header. This function is + * able to process both legacy and expanded EAP headers and in most cases, the + * caller can just use the returned payload pointer (into *plen) for processing + * the payload regardless of whether the packet used the expanded EAP header or + * not. + */ +const u8* ICACHE_FLASH_ATTR eap_hdr_validate(int vendor, EapType eap_type, + const struct wpabuf* msg, size_t* plen) +{ + const struct eap_hdr* hdr; + const u8* pos; + size_t len; + + if (!eap_hdr_len_valid(msg, 1)) { + return NULL; + } + + hdr = wpabuf_head(msg); + len = be_to_host16(hdr->length); + pos = (const u8*)(hdr + 1); + + if (*pos == EAP_TYPE_EXPANDED) { + int exp_vendor; + u32 exp_type; + + if (len < sizeof(*hdr) + 8) { + wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP " + "length"); + return NULL; + } + + pos++; + exp_vendor = WPA_GET_BE24(pos); + pos += 3; + exp_type = WPA_GET_BE32(pos); + pos += 4; + + if (exp_vendor != vendor || exp_type != (u32) eap_type) { + wpa_printf(MSG_INFO, "EAP: Invalid expanded frame " + "type"); + return NULL; + } + + *plen = len - sizeof(*hdr) - 8; + return pos; + } else { + if (vendor != EAP_VENDOR_IETF || *pos != eap_type) { + wpa_printf(MSG_INFO, "EAP: Invalid frame type"); + return NULL; + } + + *plen = len - sizeof(*hdr) - 1; + return pos + 1; + } +} + + +/** + * eap_msg_alloc - Allocate a buffer for an EAP message + * @vendor: Vendor-Id (0 = IETF) + * @type: EAP type + * @payload_len: Payload length in bytes (data after Type) + * @code: Message Code (EAP_CODE_*) + * @identifier: Identifier + * Returns: Pointer to the allocated message buffer or %NULL on error + * + * This function can be used to allocate a buffer for an EAP message and fill + * in the EAP header. This function is automatically using expanded EAP header + * if the selected Vendor-Id is not IETF. In other words, most EAP methods do + * not need to separately select which header type to use when using this + * function to allocate the message buffers. The returned buffer has room for + * payload_len bytes and has the EAP header and Type field already filled in. + */ +struct wpabuf* ICACHE_FLASH_ATTR eap_msg_alloc(int vendor, EapType type, size_t payload_len, + u8 code, u8 identifier) +{ + struct wpabuf* buf; + struct eap_hdr* hdr; + size_t len; + + len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) + + payload_len; + buf = wpabuf_alloc(len); + + if (buf == NULL) { + return NULL; + } + + hdr = wpabuf_put(buf, sizeof(*hdr)); + hdr->code = code; + hdr->identifier = identifier; + hdr->length = host_to_be16(len); + + if (vendor == EAP_VENDOR_IETF) { + wpabuf_put_u8(buf, type); + } else { + wpabuf_put_u8(buf, EAP_TYPE_EXPANDED); + wpabuf_put_be24(buf, vendor); + wpabuf_put_be32(buf, type); + } + + return buf; +} + + +/** + * eap_update_len - Update EAP header length + * @msg: EAP message from eap_msg_alloc + * + * This function updates the length field in the EAP header to match with the + * current length for the buffer. This allows eap_msg_alloc() to be used to + * allocate a larger buffer than the exact message length (e.g., if exact + * message length is not yet known). + */ +void ICACHE_FLASH_ATTR eap_update_len(struct wpabuf* msg) +{ + struct eap_hdr* hdr; + hdr = wpabuf_mhead(msg); + + if (wpabuf_len(msg) < sizeof(*hdr)) { + return; + } + + hdr->length = host_to_be16(wpabuf_len(msg)); +} + + +/** + * eap_get_id - Get EAP Identifier from wpabuf + * @msg: Buffer starting with an EAP header + * Returns: The Identifier field from the EAP header + */ +u8 ICACHE_FLASH_ATTR eap_get_id(const struct wpabuf* msg) +{ + const struct eap_hdr* eap; + + if (wpabuf_len(msg) < sizeof(*eap)) { + return 0; + } + + eap = wpabuf_head(msg); + return eap->identifier; +} + + +/** + * eap_get_id - Get EAP Type from wpabuf + * @msg: Buffer starting with an EAP header + * Returns: The EAP Type after the EAP header + */ +EapType ICACHE_FLASH_ATTR eap_get_type(const struct wpabuf* msg) +{ + if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1) { + return EAP_TYPE_NONE; + } + + return ((const u8*) wpabuf_head(msg))[sizeof(struct eap_hdr)]; +} diff --git a/components/wpa_supplicant/src/wps/uuid.c b/components/wpa_supplicant/src/wps/uuid.c new file mode 100644 index 00000000..4dd9c146 --- /dev/null +++ b/components/wpa_supplicant/src/wps/uuid.c @@ -0,0 +1,85 @@ +/* + * Universally Unique IDentifier (UUID) + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "rom/ets_sys.h" +#include "wpa/includes.h" +#include "wpa/common.h" +#include "wps/utils/uuid.h" + +int ICACHE_FLASH_ATTR uuid_str2bin(const char* str, u8* bin) +{ + const char* pos; + u8* opos; + + pos = str; + opos = bin; + + if (hexstr2bin(pos, opos, 4)) { + return -1; + } + + pos += 8; + opos += 4; + + if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) { + return -1; + } + + pos += 4; + opos += 2; + + if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) { + return -1; + } + + pos += 4; + opos += 2; + + if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) { + return -1; + } + + pos += 4; + opos += 2; + + if (*pos++ != '-' || hexstr2bin(pos, opos, 6)) { + return -1; + } + + return 0; +} + + +int ICACHE_FLASH_ATTR uuid_bin2str(const u8* bin, char* str, size_t max_len) +{ + int len; + len = snprintf(str, max_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x-%02x%02x%02x%02x%02x%02x", + bin[0], bin[1], bin[2], bin[3], + bin[4], bin[5], bin[6], bin[7], + bin[8], bin[9], bin[10], bin[11], + bin[12], bin[13], bin[14], bin[15]); + + if (len < 0 || (size_t) len >= max_len) { + return -1; + } + + return 0; +} + + +int ICACHE_FLASH_ATTR is_nil_uuid(const u8* uuid) +{ + int i; + + for (i = 0; i < UUID_LEN; i++) + if (uuid[i]) { + return 0; + } + + return 1; +} diff --git a/components/wpa_supplicant/src/wps/wps_attr_build.c b/components/wpa_supplicant/src/wps/wps_attr_build.c new file mode 100644 index 00000000..f32860f6 --- /dev/null +++ b/components/wpa_supplicant/src/wps/wps_attr_build.c @@ -0,0 +1,450 @@ +/* + * Wi-Fi Protected Setup - attribute building + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "rom/ets_sys.h" +#include "wps/asm/irqflags.h" +#include "wpa/includes.h" +#include "wpa/common.h" +#include "wpa/wpa_debug.h" +#include "wpa/ieee802_11_defs.h" +#include "wps/wps_i.h" +#include "crypto/aes_wrap.h" +#include "crypto/crypto.h" +#include "crypto/dh_group5.h" +#include "crypto/sha256.h" +#include "crypto/random.h" +#include "esp_wifi_osi.h" + +#define API_MUTEX_DECLARE(t) local_irq_declare(t) +#define API_MUTEX_TAKE(t) local_irq_save(t) +#define API_MUTEX_GIVE(t) local_irq_restore(t) + +extern bool system_overclock(void); +extern bool system_restoreclock(void); + +int ICACHE_FLASH_ATTR wps_build_public_key(struct wps_data* wps, struct wpabuf* msg, wps_key_mode_t mode) +{ + struct wpabuf* pubkey; + + if (mode != WPS_CALC_KEY_NO_CALC) { + + wpa_printf(MSG_DEBUG, "WPS: * Public Key"); + wpabuf_free(wps->dh_privkey); + + if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) { + wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys"); + wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey); + wps->dh_ctx = wps->wps->dh_ctx; + wps->wps->dh_ctx = NULL; + pubkey = wpabuf_dup(wps->wps->dh_pubkey); +#ifdef CONFIG_WPS_NFC + } else if (wps->dev_pw_id >= 0x10 && wps->wps->ap && + wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) { + wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys"); + wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey); + pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey); + wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey); +#endif /* CONFIG_WPS_NFC */ + } else { + wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys"); + wps->dh_privkey = NULL; + dh5_free(wps->dh_ctx); + + wpa_printf(MSG_DEBUG, "build public key start"); + API_MUTEX_DECLARE(c_tmp); + API_MUTEX_TAKE(c_tmp); + //pp_soft_wdt_stop(); + system_overclock(); + //REG_SET_BIT(0x3ff00014, BIT(0)); //change CPU to 160Mhz + //ets_update_cpu_frequency(160); + + wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey); + system_restoreclock(); + //REG_CLR_BIT(0x3ff00014, BIT(0)); //change CPU to 80Mhz + //ets_update_cpu_frequency(80); + + //pp_soft_wdt_restart(); + API_MUTEX_GIVE(c_tmp); + + wpa_printf(MSG_DEBUG, "build public key finish"); + + pubkey = wpabuf_zeropad(pubkey, 192); + } + + if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Failed to initialize " + "Diffie-Hellman handshake"); + wpabuf_free(pubkey); + return -1; + } + + wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey); + wpa_hexdump_buf(MSG_DEBUG, "WPS: DH own Public Key", pubkey); + + if (wps->registrar) { + wpabuf_free(wps->dh_pubkey_r); + wps->dh_pubkey_r = pubkey; + } else { + wpabuf_free(wps->dh_pubkey_e); + wps->dh_pubkey_e = pubkey; + } + + } + + if (mode != WPS_CALC_KEY_PRE_CALC) { + if (wps->registrar) { + pubkey = wps->dh_pubkey_r; + } else { + pubkey = wps->dh_pubkey_e; + } + + wpabuf_put_be16(msg, ATTR_PUBLIC_KEY); + wpabuf_put_be16(msg, wpabuf_len(pubkey)); + wpabuf_put_buf(msg, pubkey); + } + + return 0; +} + +int ICACHE_FLASH_ATTR wps_build_req_type(struct wpabuf* msg, enum wps_request_type type) +{ + wpa_printf(MSG_DEBUG, "WPS: * Request Type"); + wpabuf_put_be16(msg, ATTR_REQUEST_TYPE); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, type); + return 0; +} + +int ICACHE_FLASH_ATTR wps_build_resp_type(struct wpabuf* msg, enum wps_response_type type) +{ + wpa_printf(MSG_DEBUG, "WPS: * Response Type (%d)", type); + wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, type); + return 0; +} + +int ICACHE_FLASH_ATTR wps_build_config_methods(struct wpabuf* msg, u16 methods) +{ + wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods); + wpabuf_put_be16(msg, ATTR_CONFIG_METHODS); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, methods); + return 0; +} + +int ICACHE_FLASH_ATTR wps_build_uuid_e(struct wpabuf* msg, const u8* uuid) +{ + wpa_printf(MSG_DEBUG, "WPS: * UUID-E"); + wpabuf_put_be16(msg, ATTR_UUID_E); + wpabuf_put_be16(msg, WPS_UUID_LEN); + wpabuf_put_data(msg, uuid, WPS_UUID_LEN); + return 0; +} + +int ICACHE_FLASH_ATTR wps_build_dev_password_id(struct wpabuf* msg, u16 id) +{ + wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id); + wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, id); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_config_error(struct wpabuf* msg, u16 err) +{ + wpa_printf(MSG_DEBUG, "WPS: * Configuration Error (%d)", err); + wpabuf_put_be16(msg, ATTR_CONFIG_ERROR); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, err); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_authenticator(struct wps_data* wps, struct wpabuf* msg) +{ + u8 hash[SHA256_MAC_LEN]; + const u8* addr[2]; + size_t len[2]; + + if (wps->last_msg == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Last message not available for " + "building authenticator"); + return -1; + } + + /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) + * (M_curr* is M_curr without the Authenticator attribute) + */ + addr[0] = wpabuf_head(wps->last_msg); + len[0] = wpabuf_len(wps->last_msg); + addr[1] = wpabuf_head(msg); + len[1] = wpabuf_len(msg); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); + + wpa_printf(MSG_DEBUG, "WPS: * Authenticator"); + wpabuf_put_be16(msg, ATTR_AUTHENTICATOR); + wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN); + wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN); + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_version(struct wpabuf* msg) +{ + /* + * Note: This attribute is deprecated and set to hardcoded 0x10 for + * backwards compatibility reasons. The real version negotiation is + * done with Version2. + */ + wpa_printf(MSG_DEBUG, "WPS: * Version (hardcoded 0x10)"); + wpabuf_put_be16(msg, ATTR_VERSION); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, 0x10); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_wfa_ext(struct wpabuf* msg, int req_to_enroll, + const u8* auth_macs, size_t auth_macs_count) +{ +#ifdef CONFIG_WPS2 + u8* len; + + wpabuf_put_be16(msg, ATTR_VENDOR_EXT); + len = wpabuf_put(msg, 2); /* to be filled */ + wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA); + + wpa_printf(MSG_DEBUG, "WPS: * Version2 (0x%x)", WPS_VERSION); + wpabuf_put_u8(msg, WFA_ELEM_VERSION2); + wpabuf_put_u8(msg, 1); + wpabuf_put_u8(msg, WPS_VERSION); + + if (req_to_enroll) { + wpa_printf(MSG_DEBUG, "WPS: * Request to Enroll (1)"); + wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL); + wpabuf_put_u8(msg, 1); + wpabuf_put_u8(msg, 1); + } + + if (auth_macs && auth_macs_count) { + size_t i; + wpa_printf(MSG_DEBUG, "WPS: * AuthorizedMACs (count=%d)", + (int) auth_macs_count); + wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS); + wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN); + wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN); + + for (i = 0; i < auth_macs_count; i++) + wpa_printf(MSG_DEBUG, "WPS: AuthorizedMAC: " MACSTR, + MAC2STR(&auth_macs[i * ETH_ALEN])); + } + + WPA_PUT_BE16(len, (u8*) wpabuf_put(msg, 0) - len - 2); +#endif /* CONFIG_WPS2 */ + +#ifdef CONFIG_WPS_TESTING + + if (WPS_VERSION > 0x20) { + wpa_printf(MSG_DEBUG, "WPS: * Extensibility Testing - extra " + "attribute"); + wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, 42); + } + +#endif /* CONFIG_WPS_TESTING */ + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_msg_type(struct wpabuf* msg, enum wps_msg_type msg_type) +{ + wpa_printf(MSG_DEBUG, "WPS: * Message Type (%d)", msg_type); + wpabuf_put_be16(msg, ATTR_MSG_TYPE); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, msg_type); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_enrollee_nonce(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * Enrollee Nonce"); + wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE); + wpabuf_put_be16(msg, WPS_NONCE_LEN); + wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_registrar_nonce(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * Registrar Nonce"); + wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); + wpabuf_put_be16(msg, WPS_NONCE_LEN); + wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_auth_type_flags(struct wps_data* wps, struct wpabuf* msg) +{ + u16 auth_types = WPS_AUTH_TYPES; +#ifdef CONFIG_WPS2 + auth_types &= ~WPS_AUTH_SHARED; +#endif /* CONFIG_WPS2 */ + wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags"); + wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, auth_types); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_encr_type_flags(struct wps_data* wps, struct wpabuf* msg) +{ + u16 encr_types = WPS_ENCR_TYPES; +#ifdef CONFIG_WPS2 + encr_types &= ~WPS_ENCR_WEP; +#endif /* CONFIG_WPS2 */ + wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags"); + wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, encr_types); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_conn_type_flags(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * Connection Type Flags"); + wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, WPS_CONN_ESS); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_assoc_state(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * Association State"); + wpabuf_put_be16(msg, ATTR_ASSOC_STATE); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_key_wrap_auth(struct wps_data* wps, struct wpabuf* msg) +{ + u8 hash[SHA256_MAC_LEN]; + + wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator"); + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg), + wpabuf_len(msg), hash); + + wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH); + wpabuf_put_be16(msg, WPS_KWA_LEN); + wpabuf_put_data(msg, hash, WPS_KWA_LEN); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_encr_settings(struct wps_data* wps, struct wpabuf* msg, + struct wpabuf* plain) +{ + size_t pad_len; + const size_t block_size = 16; + u8* iv, *data; + + wpa_printf(MSG_DEBUG, "WPS: * Encrypted Settings"); + + /* PKCS#5 v2.0 pad */ + pad_len = block_size - wpabuf_len(plain) % block_size; + os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len); + + wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS); + wpabuf_put_be16(msg, block_size + wpabuf_len(plain)); + + iv = wpabuf_put(msg, block_size); + + if (random_get_bytes(iv, block_size) < 0) { + return -1; + } + + data = wpabuf_put(msg, 0); + wpabuf_put_buf(msg, plain); + + if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain))) { + return -1; + } + + return 0; +} + + +#ifdef CONFIG_WPS_OOB +int ICACHE_FLASH_ATTR wps_build_oob_dev_pw(struct wpabuf* msg, u16 dev_pw_id, + const struct wpabuf* pubkey, const u8* dev_pw, + size_t dev_pw_len) +{ + size_t hash_len; + const u8* addr[1]; + u8 pubkey_hash[WPS_HASH_LEN]; + + addr[0] = wpabuf_head(pubkey); + hash_len = wpabuf_len(pubkey); + sha256_vector(1, addr, &hash_len, pubkey_hash); + + wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD); + wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len); + wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); + wpabuf_put_be16(msg, dev_pw_id); + wpabuf_put_data(msg, dev_pw, dev_pw_len); + + return 0; +} +#endif /* CONFIG_WPS_OOB */ + + +/* Encapsulate WPS IE data with one (or more, if needed) IE headers */ +struct wpabuf* ICACHE_FLASH_ATTR wps_ie_encapsulate(struct wpabuf* data) +{ + struct wpabuf* ie; + const u8* pos, *end; + + ie = wpabuf_alloc(wpabuf_len(data) + 100); + + if (ie == NULL) { + wpabuf_free(data); + return NULL; + } + + pos = wpabuf_head(data); + end = pos + wpabuf_len(data); + + while (end > pos) { + size_t frag_len = end - pos; + + if (frag_len > 251) { + frag_len = 251; + } + + wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); + wpabuf_put_u8(ie, 4 + frag_len); + wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); + wpabuf_put_data(ie, pos, frag_len); + pos += frag_len; + } + + wpabuf_free(data); + + return ie; +} diff --git a/components/wpa_supplicant/src/wps/wps_attr_parse.c b/components/wpa_supplicant/src/wps/wps_attr_parse.c new file mode 100644 index 00000000..a7eb056f --- /dev/null +++ b/components/wpa_supplicant/src/wps/wps_attr_parse.c @@ -0,0 +1,769 @@ +/* + * Wi-Fi Protected Setup - attribute parsing + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "rom/ets_sys.h" +#include "wpa/includes.h" +#include "wpa/common.h" +#include "wps/wps_defs.h" +#include "wps/wps_attr_parse.h" + +#ifndef CONFIG_WPS_STRICT +#define WPS_WORKAROUNDS +#endif /* CONFIG_WPS_STRICT */ + + +static int ICACHE_FLASH_ATTR wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr* attr, + u8 id, u8 len, const u8* pos) +{ + wpa_printf(MSG_EXCESSIVE, "WPS: WFA subelement id=%u len=%u", + id, len); + + switch (id) { + case WFA_ELEM_VERSION2: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length " + "%u", len); + return -1; + } + + attr->version2 = pos; + break; + + case WFA_ELEM_AUTHORIZEDMACS: + attr->authorized_macs = pos; + attr->authorized_macs_len = len; + break; + + case WFA_ELEM_NETWORK_KEY_SHAREABLE: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key " + "Shareable length %u", len); + return -1; + } + + attr->network_key_shareable = pos; + break; + + case WFA_ELEM_REQUEST_TO_ENROLL: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll " + "length %u", len); + return -1; + } + + attr->request_to_enroll = pos; + break; + + case WFA_ELEM_SETTINGS_DELAY_TIME: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay " + "Time length %u", len); + return -1; + } + + attr->settings_delay_time = pos; + break; + + default: + wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor " + "Extension subelement %u", id); + break; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_parse_vendor_ext_wfa(struct wps_parse_attr* attr, const u8* pos, + u16 len) +{ + const u8* end = pos + len; + u8 id, elen; + + while (pos + 2 < end) { + id = *pos++; + elen = *pos++; + + if (pos + elen > end) { + break; + } + + if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0) { + return -1; + } + + pos += elen; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_parse_vendor_ext(struct wps_parse_attr* attr, const u8* pos, + u16 len) +{ + u32 vendor_id; + + if (len < 3) { + wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension"); + return 0; + } + + vendor_id = WPA_GET_BE24(pos); + + switch (vendor_id) { + case WPS_VENDOR_ID_WFA: + return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3); + } + + /* Handle unknown vendor extensions */ + + wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)", + vendor_id); + + if (len > WPS_MAX_VENDOR_EXT_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)", + len); + return -1; + } + + if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) { + wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension " + "attribute (max %d vendor extensions)", + MAX_WPS_PARSE_VENDOR_EXT); + return -1; + } + + attr->vendor_ext[attr->num_vendor_ext] = pos; + attr->vendor_ext_len[attr->num_vendor_ext] = len; + attr->num_vendor_ext++; + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_set_attr(struct wps_parse_attr* attr, u16 type, + const u8* pos, u16 len) +{ + switch (type) { + case ATTR_VERSION: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u", + len); + return -1; + } + + attr->version = pos; + break; + + case ATTR_MSG_TYPE: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type " + "length %u", len); + return -1; + } + + attr->msg_type = pos; + break; + + case ATTR_ENROLLEE_NONCE: + if (len != WPS_NONCE_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce " + "length %u", len); + return -1; + } + + attr->enrollee_nonce = pos; + break; + + case ATTR_REGISTRAR_NONCE: + if (len != WPS_NONCE_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce " + "length %u", len); + return -1; + } + + attr->registrar_nonce = pos; + break; + + case ATTR_UUID_E: + if (len != WPS_UUID_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u", + len); + return -1; + } + + attr->uuid_e = pos; + break; + + case ATTR_UUID_R: + if (len != WPS_UUID_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u", + len); + return -1; + } + + attr->uuid_r = pos; + break; + + case ATTR_AUTH_TYPE_FLAGS: + if (len != 2) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " + "Type Flags length %u", len); + return -1; + } + + attr->auth_type_flags = pos; + break; + + case ATTR_ENCR_TYPE_FLAGS: + if (len != 2) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type " + "Flags length %u", len); + return -1; + } + + attr->encr_type_flags = pos; + break; + + case ATTR_CONN_TYPE_FLAGS: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type " + "Flags length %u", len); + return -1; + } + + attr->conn_type_flags = pos; + break; + + case ATTR_CONFIG_METHODS: + if (len != 2) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods " + "length %u", len); + return -1; + } + + attr->config_methods = pos; + break; + + case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS: + if (len != 2) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Selected " + "Registrar Config Methods length %u", len); + return -1; + } + + attr->sel_reg_config_methods = pos; + break; + + case ATTR_PRIMARY_DEV_TYPE: + if (len != WPS_DEV_TYPE_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device " + "Type length %u", len); + return -1; + } + + attr->primary_dev_type = pos; + break; + + case ATTR_RF_BANDS: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length " + "%u", len); + return -1; + } + + attr->rf_bands = pos; + break; + + case ATTR_ASSOC_STATE: + if (len != 2) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Association State " + "length %u", len); + return -1; + } + + attr->assoc_state = pos; + break; + + case ATTR_CONFIG_ERROR: + if (len != 2) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration " + "Error length %u", len); + return -1; + } + + attr->config_error = pos; + break; + + case ATTR_DEV_PASSWORD_ID: + if (len != 2) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password " + "ID length %u", len); + return -1; + } + + attr->dev_password_id = pos; + break; + + case ATTR_OOB_DEVICE_PASSWORD: + if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 + + WPS_OOB_DEVICE_PASSWORD_MIN_LEN || + len > WPS_OOB_PUBKEY_HASH_LEN + 2 + + WPS_OOB_DEVICE_PASSWORD_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device " + "Password length %u", len); + return -1; + } + + attr->oob_dev_password = pos; + attr->oob_dev_password_len = len; + break; + + case ATTR_OS_VERSION: + if (len != 4) { + wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length " + "%u", len); + return -1; + } + + attr->os_version = pos; + break; + + case ATTR_WPS_STATE: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected " + "Setup State length %u", len); + return -1; + } + + attr->wps_state = pos; + break; + + case ATTR_AUTHENTICATOR: + if (len != WPS_AUTHENTICATOR_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator " + "length %u", len); + return -1; + } + + attr->authenticator = pos; + break; + + case ATTR_R_HASH1: + if (len != WPS_HASH_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u", + len); + return -1; + } + + attr->r_hash1 = pos; + break; + + case ATTR_R_HASH2: + if (len != WPS_HASH_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u", + len); + return -1; + } + + attr->r_hash2 = pos; + break; + + case ATTR_E_HASH1: + if (len != WPS_HASH_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u", + len); + return -1; + } + + attr->e_hash1 = pos; + break; + + case ATTR_E_HASH2: + if (len != WPS_HASH_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u", + len); + return -1; + } + + attr->e_hash2 = pos; + break; + + case ATTR_R_SNONCE1: + if (len != WPS_SECRET_NONCE_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length " + "%u", len); + return -1; + } + + attr->r_snonce1 = pos; + break; + + case ATTR_R_SNONCE2: + if (len != WPS_SECRET_NONCE_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length " + "%u", len); + return -1; + } + + attr->r_snonce2 = pos; + break; + + case ATTR_E_SNONCE1: + if (len != WPS_SECRET_NONCE_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length " + "%u", len); + return -1; + } + + attr->e_snonce1 = pos; + break; + + case ATTR_E_SNONCE2: + if (len != WPS_SECRET_NONCE_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length " + "%u", len); + return -1; + } + + attr->e_snonce2 = pos; + break; + + case ATTR_KEY_WRAP_AUTH: + if (len != WPS_KWA_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap " + "Authenticator length %u", len); + return -1; + } + + attr->key_wrap_auth = pos; + break; + + case ATTR_AUTH_TYPE: + if (len != 2) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " + "Type length %u", len); + return -1; + } + + attr->auth_type = pos; + break; + + case ATTR_ENCR_TYPE: + if (len != 2) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption " + "Type length %u", len); + return -1; + } + + attr->encr_type = pos; + break; + + case ATTR_NETWORK_INDEX: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index " + "length %u", len); + return -1; + } + + attr->network_idx = pos; + break; + + case ATTR_NETWORK_KEY_INDEX: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index " + "length %u", len); + return -1; + } + + attr->network_key_idx = pos; + break; + + case ATTR_MAC_ADDR: + if (len != ETH_ALEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address " + "length %u", len); + return -1; + } + + attr->mac_addr = pos; + break; + + case ATTR_KEY_PROVIDED_AUTO: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided " + "Automatically length %u", len); + return -1; + } + + attr->key_prov_auto = pos; + break; + + case ATTR_802_1X_ENABLED: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled " + "length %u", len); + return -1; + } + + attr->dot1x_enabled = pos; + break; + + case ATTR_SELECTED_REGISTRAR: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar" + " length %u", len); + return -1; + } + + attr->selected_registrar = pos; + break; + + case ATTR_REQUEST_TYPE: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type " + "length %u", len); + return -1; + } + + attr->request_type = pos; + break; + + case ATTR_RESPONSE_TYPE: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type " + "length %u", len); + return -1; + } + + attr->response_type = pos; + break; + + case ATTR_MANUFACTURER: + attr->manufacturer = pos; + attr->manufacturer_len = len; + break; + + case ATTR_MODEL_NAME: + attr->model_name = pos; + attr->model_name_len = len; + break; + + case ATTR_MODEL_NUMBER: + attr->model_number = pos; + attr->model_number_len = len; + break; + + case ATTR_SERIAL_NUMBER: + attr->serial_number = pos; + attr->serial_number_len = len; + break; + + case ATTR_DEV_NAME: + attr->dev_name = pos; + attr->dev_name_len = len; + break; + + case ATTR_PUBLIC_KEY: + attr->public_key = pos; + attr->public_key_len = len; + break; + + case ATTR_ENCR_SETTINGS: + attr->encr_settings = pos; + attr->encr_settings_len = len; + break; + + case ATTR_CRED: + if (attr->num_cred >= MAX_CRED_COUNT) { + wpa_printf(MSG_DEBUG, "WPS: Skipped Credential " + "attribute (max %d credentials)", + MAX_CRED_COUNT); + break; + } + + attr->cred[attr->num_cred] = pos; + attr->cred_len[attr->num_cred] = len; + attr->num_cred++; + break; + + case ATTR_SSID: + attr->ssid = pos; + attr->ssid_len = len; + break; + + case ATTR_NETWORK_KEY: + attr->network_key = pos; + attr->network_key_len = len; + break; + + case ATTR_EAP_TYPE: + attr->eap_type = pos; + attr->eap_type_len = len; + break; + + case ATTR_EAP_IDENTITY: + attr->eap_identity = pos; + attr->eap_identity_len = len; + break; + + case ATTR_AP_SETUP_LOCKED: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked " + "length %u", len); + return -1; + } + + attr->ap_setup_locked = pos; + break; + + case ATTR_REQUESTED_DEV_TYPE: + if (len != WPS_DEV_TYPE_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device " + "Type length %u", len); + return -1; + } + + if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) { + wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device " + "Type attribute (max %u types)", + MAX_REQ_DEV_TYPE_COUNT); + break; + } + + attr->req_dev_type[attr->num_req_dev_type] = pos; + attr->num_req_dev_type++; + break; + + case ATTR_SECONDARY_DEV_TYPE_LIST: + if (len > WPS_SEC_DEV_TYPE_MAX_LEN || + (len % WPS_DEV_TYPE_LEN) > 0) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Secondary Device " + "Type length %u", len); + return -1; + } + + attr->sec_dev_type_list = pos; + attr->sec_dev_type_list_len = len; + break; + + case ATTR_VENDOR_EXT: + if (wps_parse_vendor_ext(attr, pos, len) < 0) { + return -1; + } + + break; + + case ATTR_AP_CHANNEL: + if (len != 2) { + wpa_printf(MSG_DEBUG, "WPS: Invalid AP Channel " + "length %u", len); + return -1; + } + + attr->ap_channel = pos; + break; + + default: + wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x " + "len=%u", type, len); + break; + } + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_parse_msg(const struct wpabuf* msg, struct wps_parse_attr* attr) +{ + const u8* pos, *end; + u16 type, len; +#ifdef WPS_WORKAROUNDS + u16 prev_type = 0; +#endif /* WPS_WORKAROUNDS */ + + os_memset(attr, 0, sizeof(*attr)); + pos = wpabuf_head(msg); + end = pos + wpabuf_len(msg); + + while (pos < end) { + if (end - pos < 4) { + wpa_printf(MSG_DEBUG, "WPS: Invalid message - " + "%lu bytes remaining", + (unsigned long)(end - pos)); + return -1; + } + + type = WPA_GET_BE16(pos); + pos += 2; + len = WPA_GET_BE16(pos); + pos += 2; + wpa_printf(MSG_EXCESSIVE, "WPS: attr type=0x%x len=%u", + type, len); + + if (len > end - pos) { + wpa_printf(MSG_DEBUG, "WPS: Attribute overflow"); + wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg); +#ifdef WPS_WORKAROUNDS + + /* + * Some deployed APs seem to have a bug in encoding of + * Network Key attribute in the Credential attribute + * where they add an extra octet after the Network Key + * attribute at least when open network is being + * provisioned. + */ + if ((type & 0xff00) != 0x1000 && + prev_type == ATTR_NETWORK_KEY) { + wpa_printf(MSG_DEBUG, "WPS: Workaround - try " + "to skip unexpected octet after " + "Network Key"); + pos -= 3; + continue; + } + +#endif /* WPS_WORKAROUNDS */ + return -1; + } + +#ifdef WPS_WORKAROUNDS + + if (type == 0 && len == 0) { + /* + * Mac OS X 10.6 seems to be adding 0x00 padding to the + * end of M1. Skip those to avoid interop issues. + */ + int i; + + for (i = 0; i < end - pos; i++) { + if (pos[i]) { + break; + } + } + + if (i == end - pos) { + wpa_printf(MSG_DEBUG, "WPS: Workaround - skip " + "unexpected message padding"); + break; + } + } + +#endif /* WPS_WORKAROUNDS */ + + if (wps_set_attr(attr, type, pos, len) < 0) { + return -1; + } + +#ifdef WPS_WORKAROUNDS + prev_type = type; +#endif /* WPS_WORKAROUNDS */ + pos += len; + } + + return 0; +} diff --git a/components/wpa_supplicant/src/wps/wps_attr_process.c b/components/wpa_supplicant/src/wps/wps_attr_process.c new file mode 100644 index 00000000..28e77ebb --- /dev/null +++ b/components/wpa_supplicant/src/wps/wps_attr_process.c @@ -0,0 +1,358 @@ +/* + * Wi-Fi Protected Setup - attribute processing + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "rom/ets_sys.h" +#include "wpa/includes.h" +#include "wpa/common.h" +#include "wps/wps_i.h" +#include "crypto/sha256.h" + +int ICACHE_FLASH_ATTR wps_process_authenticator(struct wps_data* wps, const u8* authenticator, + const struct wpabuf* msg) +{ + u8 hash[SHA256_MAC_LEN]; + const u8* addr[2]; + size_t len[2]; + + if (authenticator == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute " + "included"); + return -1; + } + + if (wps->last_msg == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Last message not available for " + "validating authenticator"); + return -1; + } + + /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) + * (M_curr* is M_curr without the Authenticator attribute) + */ + addr[0] = wpabuf_head(wps->last_msg); + len[0] = wpabuf_len(wps->last_msg); + addr[1] = wpabuf_head(msg); + len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN; + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); + + if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator"); + return -1; + } + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_process_key_wrap_auth(struct wps_data* wps, struct wpabuf* msg, + const u8* key_wrap_auth) +{ + u8 hash[SHA256_MAC_LEN]; + const u8* head; + size_t len; + + if (key_wrap_auth == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute"); + return -1; + } + + head = wpabuf_head(msg); + len = wpabuf_len(msg) - 4 - WPS_KWA_LEN; + + if (head + len != key_wrap_auth - 4) { + wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the " + "decrypted attribute"); + return -1; + } + + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash); + + if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Invalid KWA"); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_network_idx(struct wps_credential* cred, + const u8* idx) +{ + if (idx == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Credential did not include " + "Network Index"); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_ssid(struct wps_credential* cred, const u8* ssid, + size_t ssid_len) +{ + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID"); + return -1; + } + + /* Remove zero-padding since some Registrar implementations seem to use + * hardcoded 32-octet length for this attribute */ + while (ssid_len > 0 && ssid[ssid_len - 1] == 0) { + ssid_len--; + } + + wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len); + + if (ssid_len <= sizeof(cred->ssid)) { + os_memcpy(cred->ssid, ssid, ssid_len); + cred->ssid_len = ssid_len; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_auth_type(struct wps_credential* cred, + const u8* auth_type) +{ + if (auth_type == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Credential did not include " + "Authentication Type"); + return -1; + } + + cred->auth_type = WPA_GET_BE16(auth_type); + wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x", + cred->auth_type); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_encr_type(struct wps_credential* cred, + const u8* encr_type) +{ + if (encr_type == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Credential did not include " + "Encryption Type"); + return -1; + } + + cred->encr_type = WPA_GET_BE16(encr_type); + wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x", + cred->encr_type); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_network_key_idx(struct wps_credential* cred, + const u8* key_idx) +{ + if (key_idx == NULL) { + return 0; /* optional attribute */ + } + + wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx); + cred->key_idx = *key_idx; + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_network_key(struct wps_credential* cred, + const u8* key, size_t key_len) +{ + if (key == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Credential did not include " + "Network Key"); + + if (cred->auth_type == WPS_AUTH_OPEN && + cred->encr_type == WPS_ENCR_NONE) { + wpa_printf(MSG_DEBUG, "WPS: Workaround - Allow " + "missing mandatory Network Key attribute " + "for open network"); + return 0; + } + + return -1; + } + + wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len); + + if (key_len <= sizeof(cred->key)) { + os_memcpy(cred->key, key, key_len); + cred->key_len = key_len; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_mac_addr(struct wps_credential* cred, + const u8* mac_addr) +{ + if (mac_addr == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Credential did not include " + "MAC Address"); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr)); + os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_eap_type(struct wps_credential* cred, + const u8* eap_type, size_t eap_type_len) +{ + if (eap_type == NULL) { + return 0; /* optional attribute */ + } + + wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_eap_identity(struct wps_credential* cred, + const u8* identity, + size_t identity_len) +{ + if (identity == NULL) { + return 0; /* optional attribute */ + } + + wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity", + identity, identity_len); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_key_prov_auto(struct wps_credential* cred, + const u8* key_prov_auto) +{ + if (key_prov_auto == NULL) { + return 0; /* optional attribute */ + } + + wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d", + *key_prov_auto); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_802_1x_enabled(struct wps_credential* cred, + const u8* dot1x_enabled) +{ + if (dot1x_enabled == NULL) { + return 0; /* optional attribute */ + } + + wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_ap_channel(struct wps_credential* cred, + const u8* ap_channel) +{ + if (ap_channel == NULL) { + return 0; /* optional attribute */ + } + + cred->ap_channel = WPA_GET_BE16(ap_channel); + wpa_printf(MSG_DEBUG, "WPS: AP Channel: %u", cred->ap_channel); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_workaround_cred_key(struct wps_credential* cred) +{ + if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) && + cred->key_len > 8 && cred->key_len < 64 && + cred->key[cred->key_len - 1] == 0) { +#ifdef CONFIG_WPS_STRICT + wpa_printf(MSG_INFO, "WPS: WPA/WPA2-Personal passphrase uses " + "forbidden NULL termination"); + wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key", + cred->key, cred->key_len); + return -1; +#else /* CONFIG_WPS_STRICT */ + /* + * A deployed external registrar is known to encode ASCII + * passphrases incorrectly. Remove the extra NULL termination + * to fix the encoding. + */ + wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL " + "termination from ASCII passphrase"); + cred->key_len--; +#endif /* CONFIG_WPS_STRICT */ + } + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_process_cred(struct wps_parse_attr* attr, + struct wps_credential* cred) +{ + wpa_printf(MSG_DEBUG, "WPS: Process Credential"); + + /* TODO: support multiple Network Keys */ + if (wps_process_cred_network_idx(cred, attr->network_idx) || + wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) || + wps_process_cred_auth_type(cred, attr->auth_type) || + wps_process_cred_encr_type(cred, attr->encr_type) || + wps_process_cred_network_key_idx(cred, attr->network_key_idx) || + wps_process_cred_network_key(cred, attr->network_key, + attr->network_key_len) || + wps_process_cred_mac_addr(cred, attr->mac_addr) || + wps_process_cred_eap_type(cred, attr->eap_type, + attr->eap_type_len) || + wps_process_cred_eap_identity(cred, attr->eap_identity, + attr->eap_identity_len) || + wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) || + wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled) || + wps_process_cred_ap_channel(cred, attr->ap_channel)) { + return -1; + } + + return wps_workaround_cred_key(cred); +} + + +int ICACHE_FLASH_ATTR wps_process_ap_settings(struct wps_parse_attr* attr, + struct wps_credential* cred) +{ + wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings"); + os_memset(cred, 0, sizeof(*cred)); + + /* TODO: optional attributes New Password and Device Password ID */ + if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) || + wps_process_cred_auth_type(cred, attr->auth_type) || + wps_process_cred_encr_type(cred, attr->encr_type) || + wps_process_cred_network_key_idx(cred, attr->network_key_idx) || + wps_process_cred_network_key(cred, attr->network_key, + attr->network_key_len) || + wps_process_cred_mac_addr(cred, attr->mac_addr)) { + return -1; + } + + return wps_workaround_cred_key(cred); +} diff --git a/components/wpa_supplicant/src/wps/wps_common.c b/components/wpa_supplicant/src/wps/wps_common.c new file mode 100644 index 00000000..695668c6 --- /dev/null +++ b/components/wpa_supplicant/src/wps/wps_common.c @@ -0,0 +1,706 @@ +/* + * Wi-Fi Protected Setup - common functionality + * Copyright (c) 2008-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include + +#include "rom/ets_sys.h" +#include "wpa/includes.h" +#include "wpa/common.h" +#include "wps/wps_i.h" + +#include "crypto/aes_wrap.h" +#include "crypto/crypto.h" +#include "crypto/dh_group5.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "crypto/random.h" + +#include "esp_system.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +void ICACHE_FLASH_ATTR wps_kdf(const u8* key, const u8* label_prefix, size_t label_prefix_len, + const char* label, u8* res, size_t res_len) +{ + u8 i_buf[4], key_bits[4]; + const u8* addr[4]; + size_t len[4]; + int i, iter; + u8 hash[SHA256_MAC_LEN], *opos; + size_t left; + + WPA_PUT_BE32(key_bits, res_len * 8); + + addr[0] = i_buf; + len[0] = sizeof(i_buf); + addr[1] = label_prefix; + len[1] = label_prefix_len; + addr[2] = (const u8*) label; + len[2] = os_strlen(label); + addr[3] = key_bits; + len[3] = sizeof(key_bits); + + iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN; + opos = res; + left = res_len; + + for (i = 1; i <= iter; i++) { + WPA_PUT_BE32(i_buf, i); + hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); + + if (i < iter) { + os_memcpy(opos, hash, SHA256_MAC_LEN); + opos += SHA256_MAC_LEN; + left -= SHA256_MAC_LEN; + } else { + os_memcpy(opos, hash, left); + } + } +} + +int ICACHE_FLASH_ATTR wps_derive_keys(struct wps_data* wps) +{ + struct wpabuf* pubkey, *dh_shared; + u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN]; + const u8* addr[3]; + size_t len[3]; + u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN]; + + if (wps->dh_privkey == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available"); + return -1; + } + + pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r; + + if (pubkey == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available"); + return -1; + } + + wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey); + wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey); + //printf("[%s]line:[%d]%d\r\n", __func__, __LINE__, REG_READ(0x3ff20c00)); + dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey); + //printf("[%s]line:[%d]%d\r\n", __func__, __LINE__, REG_READ(0x3ff20c00)); + + dh5_free(wps->dh_ctx); + wps->dh_ctx = NULL; + dh_shared = wpabuf_zeropad(dh_shared, 192); + + if (dh_shared == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); + return -1; + } + + /* Own DH private key is not needed anymore */ + wpabuf_free(wps->dh_privkey); + wps->dh_privkey = NULL; + + wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared); + + /* DHKey = SHA-256(g^AB mod p) */ + addr[0] = wpabuf_head(dh_shared); + len[0] = wpabuf_len(dh_shared); + sha256_vector(1, addr, len, dhkey); + wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); + wpabuf_free(dh_shared); + + /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */ + addr[0] = wps->nonce_e; + len[0] = WPS_NONCE_LEN; + addr[1] = wps->mac_addr_e; + len[1] = ETH_ALEN; + addr[2] = wps->nonce_r; + len[2] = WPS_NONCE_LEN; + hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); + + wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); + + wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", + keys, sizeof(keys)); + os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN); + os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN); + os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, + WPS_EMSK_LEN); + + wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey", + wps->authkey, WPS_AUTHKEY_LEN); + wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey", + wps->keywrapkey, WPS_KEYWRAPKEY_LEN); + wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN); + + return 0; +} + + +void ICACHE_FLASH_ATTR wps_derive_psk(struct wps_data* wps, const u8* dev_passwd, + size_t dev_passwd_len) +{ + u8 hash[SHA256_MAC_LEN]; + + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, + (dev_passwd_len + 1) / 2, hash); + os_memcpy(wps->psk1, hash, WPS_PSK_LEN); + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, + dev_passwd + (dev_passwd_len + 1) / 2, + dev_passwd_len / 2, hash); + os_memcpy(wps->psk2, hash, WPS_PSK_LEN); + + wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password", + dev_passwd, dev_passwd_len); + wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN); + wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN); +} + +struct wpabuf* ICACHE_FLASH_ATTR wps_decrypt_encr_settings(struct wps_data* wps, const u8* encr, + size_t encr_len) +{ + struct wpabuf* decrypted; + const size_t block_size = 16; + size_t i; + u8 pad; + const u8* pos; + + /* AES-128-CBC */ + if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size) { + wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received"); + return NULL; + } + + decrypted = wpabuf_alloc(encr_len - block_size); + + if (decrypted == NULL) { + return NULL; + } + + wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len); + wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size); + + if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), + wpabuf_len(decrypted))) { + wpabuf_free(decrypted); + return NULL; + } + + wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings", + decrypted); + + pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1; + pad = *pos; + + if (pad > wpabuf_len(decrypted)) { + wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value"); + wpabuf_free(decrypted); + return NULL; + } + + for (i = 0; i < pad; i++) { + if (*pos-- != pad) { + wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad " + "string"); + wpabuf_free(decrypted); + return NULL; + } + } + + decrypted->used -= pad; + + return decrypted; +} + +#ifdef CONFIG_WPS_PIN +/** + * wps_pin_checksum - Compute PIN checksum + * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit) + * Returns: Checksum digit + */ +unsigned int ICACHE_FLASH_ATTR wps_pin_checksum(unsigned int pin) +{ + unsigned int accum = 0; + + while (pin) { + accum += 3 * (pin % 10); + pin /= 10; + accum += pin % 10; + pin /= 10; + } + + return (10 - accum % 10) % 10; +} + + +/** + * wps_pin_valid - Check whether a PIN has a valid checksum + * @pin: Eight digit PIN (i.e., including the checksum digit) + * Returns: 1 if checksum digit is valid, or 0 if not + */ +unsigned int ICACHE_FLASH_ATTR wps_pin_valid(unsigned int pin) +{ + return wps_pin_checksum(pin / 10) == (pin % 10); +} + + +/** + * wps_generate_pin - Generate a random PIN + * Returns: Eight digit PIN (i.e., including the checksum digit) + */ +unsigned int ICACHE_FLASH_ATTR wps_generate_pin(void) +{ + unsigned int val; + + /* Generate seven random digits for the PIN */ + //if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) { + struct os_time now; + os_get_time(&now); + val = esp_random() ^ now.sec ^ now.usec; + //} + val %= 10000000; + + /* Append checksum digit */ + return val * 10 + wps_pin_checksum(val); +} + + +int ICACHE_FLASH_ATTR wps_pin_str_valid(const char* pin) +{ + const char* p; + size_t len; + + p = pin; + + while (*p >= '0' && *p <= '9') { + p++; + } + + if (*p != '\0') { + return 0; + } + + len = p - pin; + return len == 4 || len == 8; +} +#endif + +void ICACHE_FLASH_ATTR wps_fail_event(struct wps_context* wps, enum wps_msg_type msg, + u16 config_error, u16 error_indication) +{ + union wps_event_data* data; + + data = (union wps_event_data*)os_zalloc(sizeof(union wps_event_data)); + + if (data == NULL) { + return; + } + + if (wps->event_cb == NULL) { + os_free(data); + return; + } + + os_memset(data, 0, sizeof(union wps_event_data)); + data->fail.msg = msg; + data->fail.config_error = config_error; + data->fail.error_indication = error_indication; + wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, data); + os_free(data); +} + +void ICACHE_FLASH_ATTR wps_success_event(struct wps_context* wps) +{ + if (wps->event_cb == NULL) { + return; + } + + wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL); +} + +void ICACHE_FLASH_ATTR wps_pwd_auth_fail_event(struct wps_context* wps, int enrollee, int part) +{ + union wps_event_data* data; + + data = (union wps_event_data*)os_zalloc(sizeof(union wps_event_data)); + + if (data == NULL) { + return; + } + + if (wps->event_cb == NULL) { + os_free(data); + return; + } + + os_memset(data, 0, sizeof(union wps_event_data)); + data->pwd_auth_fail.enrollee = enrollee; + data->pwd_auth_fail.part = part; + wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, data); + os_free(data); +} + +void ICACHE_FLASH_ATTR wps_pbc_overlap_event(struct wps_context* wps) +{ + if (wps->event_cb == NULL) { + return; + } + + wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL); +} + +void ICACHE_FLASH_ATTR wps_pbc_timeout_event(struct wps_context* wps) +{ + if (wps->event_cb == NULL) { + return; + } + + wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL); +} + +#ifdef CONFIG_WPS_OOB +struct wpabuf* ICACHE_FLASH_ATTR wps_get_oob_cred(struct wps_context* wps) +{ + struct wps_data* data; + struct wpabuf* plain; + + data = (struct wps_data*)os_zalloc(sizeof(struct wps_data)); + + if (data == NULL) { + return NULL; + } + + plain = wpabuf_alloc(500); + + if (plain == NULL) { + os_free(data); + wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " + "credential"); + return NULL; + } + + os_memset(data, 0, sizeof(struct wps_data)); + data->wps = wps; + data->auth_type = wps->auth_types; + data->encr_type = wps->encr_types; + + if (wps_build_version(plain) || + wps_build_cred(data, plain) || + wps_build_wfa_ext(plain, 0, NULL, 0)) { + wpabuf_free(plain); + os_free(data); + return NULL; + } + + os_free(data); + return plain; +} + +#ifdef CONFIG_WPS_NFC + +struct wpabuf* ICACHE_FLASH_ATTR wps_build_nfc_pw_token(u16 dev_pw_id, + const struct wpabuf* pubkey, + const struct wpabuf* dev_pw) +{ + struct wpabuf* data; + + data = wpabuf_alloc(200); + + if (data == NULL) { + return NULL; + } + + if (wps_build_version(data) || + wps_build_oob_dev_pw(data, dev_pw_id, pubkey, + wpabuf_head(dev_pw), wpabuf_len(dev_pw)) || + wps_build_wfa_ext(data, 0, NULL, 0)) { + wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password " + "token"); + wpabuf_free(data); + return NULL; + } + + return data; +} + +#endif + +int ICACHE_FLASH_ATTR wps_oob_use_cred(struct wps_context* wps, struct wps_parse_attr* attr) +{ + struct wpabuf msg; + size_t i; + + for (i = 0; i < attr->num_cred; i++) { + struct wps_credential local_cred; + struct wps_parse_attr cattr; + + os_memset(&local_cred, 0, sizeof(local_cred)); + wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]); + + if (wps_parse_msg(&msg, &cattr) < 0 || + wps_process_cred(&cattr, &local_cred)) { + wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB " + "credential"); + return -1; + } + + wps->cred_cb(wps->cb_ctx, &local_cred); + } + + return 0; +} +#endif /* CONFIG_WPS_OOB */ + +int ICACHE_FLASH_ATTR wps_dev_type_str2bin(const char* str, u8 dev_type[WPS_DEV_TYPE_LEN]) +{ + const char* pos; + + /* -- */ + WPA_PUT_BE16(dev_type, atoi(str)); + pos = (char*)os_strchr(str, '-'); + + if (pos == NULL) { + return -1; + } + + pos++; + + if (hexstr2bin(pos, &dev_type[2], 4)) { + return -1; + } + + pos = (char*)os_strchr(pos, '-'); + + if (pos == NULL) { + return -1; + } + + pos++; + WPA_PUT_BE16(&dev_type[6], atoi(pos)); + + + return 0; +} + +char* ICACHE_FLASH_ATTR wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char* buf, + size_t buf_len) +{ + int ret; + + ret = snprintf(buf, buf_len, "%u-%08X-%u", + WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]), + WPA_GET_BE16(&dev_type[6])); + + if (ret < 0 || (unsigned int) ret >= buf_len) { + return NULL; + } + + return buf; +} + +void ICACHE_FLASH_ATTR uuid_gen_mac_addr(const u8* mac_addr, u8* uuid) +{ + const u8* addr[2]; + size_t len[2]; + u8 hash[SHA1_MAC_LEN]; + u8 nsid[16] = { + 0x52, 0x64, 0x80, 0xf8, + 0xc9, 0x9b, + 0x4b, 0xe5, + 0xa6, 0x55, + 0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84 + }; + + addr[0] = nsid; + len[0] = sizeof(nsid); + addr[1] = mac_addr; + len[1] = 6; + sha1_vector(2, addr, len, hash); + os_memcpy(uuid, hash, 16); + + /* Version: 5 = named-based version using SHA-1 */ + uuid[6] = (5 << 4) | (uuid[6] & 0x0f); + + /* Variant specified in RFC 4122 */ + uuid[8] = 0x80 | (uuid[8] & 0x3f); +} + + +u16 ICACHE_FLASH_ATTR wps_config_methods_str2bin(const char* str) +{ + u16 methods = 0; + + if (str == NULL) { + /* Default to enabling methods based on build configuration */ + methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; +#ifdef CONFIG_WPS2 + methods |= WPS_CONFIG_VIRT_DISPLAY; +#endif /* CONFIG_WPS2 */ +#ifdef CONFIG_WPS_NFC + methods |= WPS_CONFIG_NFC_INTERFACE; +#endif /* CONFIG_WPS_NFC */ + } else { + if (os_strstr(str, "ethernet")) { + methods |= WPS_CONFIG_ETHERNET; + } + + if (os_strstr(str, "label")) { + methods |= WPS_CONFIG_LABEL; + } + + if (os_strstr(str, "display")) { + methods |= WPS_CONFIG_DISPLAY; + } + + if (os_strstr(str, "ext_nfc_token")) { + methods |= WPS_CONFIG_EXT_NFC_TOKEN; + } + + if (os_strstr(str, "int_nfc_token")) { + methods |= WPS_CONFIG_INT_NFC_TOKEN; + } + + if (os_strstr(str, "nfc_interface")) { + methods |= WPS_CONFIG_NFC_INTERFACE; + } + + if (os_strstr(str, "push_button")) { + methods |= WPS_CONFIG_PUSHBUTTON; + } + + if (os_strstr(str, "keypad")) { + methods |= WPS_CONFIG_KEYPAD; + } + +#ifdef CONFIG_WPS2 + + if (os_strstr(str, "virtual_display")) { + methods |= WPS_CONFIG_VIRT_DISPLAY; + } + + if (os_strstr(str, "physical_display")) { + methods |= WPS_CONFIG_PHY_DISPLAY; + } + + if (os_strstr(str, "virtual_push_button")) { + methods |= WPS_CONFIG_VIRT_PUSHBUTTON; + } + + if (os_strstr(str, "physical_push_button")) { + methods |= WPS_CONFIG_PHY_PUSHBUTTON; + } + +#endif /* CONFIG_WPS2 */ + } + + return methods; +} + +struct wpabuf* ICACHE_FLASH_ATTR wps_build_wsc_ack(struct wps_data* wps) +{ + struct wpabuf* msg; + + wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK"); + + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + return NULL; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_WSC_ACK) || + wps_build_enrollee_nonce(wps, msg) || + wps_build_registrar_nonce(wps, msg) || + wps_build_wfa_ext(msg, 0, NULL, 0)) { + wpabuf_free(msg); + return NULL; + } + + return msg; +} + +struct wpabuf* ICACHE_FLASH_ATTR wps_build_wsc_nack(struct wps_data* wps) +{ + struct wpabuf* msg; + + wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK"); + + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + return NULL; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_WSC_NACK) || + wps_build_enrollee_nonce(wps, msg) || + wps_build_registrar_nonce(wps, msg) || + wps_build_config_error(msg, wps->config_error) || + wps_build_wfa_ext(msg, 0, NULL, 0)) { + wpabuf_free(msg); + return NULL; + } + + return msg; +} + +#ifdef CONFIG_WPS_NFC +struct wpabuf* ICACHE_FLASH_ATTR wps_nfc_token_gen(int ndef, int* id, struct wpabuf** pubkey, + struct wpabuf** privkey, + struct wpabuf** dev_pw) +{ + struct wpabuf* priv = NULL, *pub = NULL, *pw, *ret; + void* dh_ctx; + u16 val; + + pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN); + + if (pw == NULL) { + return NULL; + } + + if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN), + WPS_OOB_DEVICE_PASSWORD_LEN) || + random_get_bytes((u8*) &val, sizeof(val))) { + wpabuf_free(pw); + return NULL; + } + + dh_ctx = dh5_init(&priv, &pub); + + if (dh_ctx == NULL) { + wpabuf_free(pw); + return NULL; + } + + dh5_free(dh_ctx); + + *id = 0x10 + val % 0xfff0; + wpabuf_free(*pubkey); + *pubkey = pub; + wpabuf_free(*privkey); + *privkey = priv; + wpabuf_free(*dev_pw); + *dev_pw = pw; + + ret = wps_build_nfc_pw_token(*id, *pubkey, *dev_pw); + + 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 */ diff --git a/components/wpa_supplicant/src/wps/wps_dev_attr.c b/components/wpa_supplicant/src/wps/wps_dev_attr.c new file mode 100644 index 00000000..c9d9c44a --- /dev/null +++ b/components/wpa_supplicant/src/wps/wps_dev_attr.c @@ -0,0 +1,500 @@ +/* + * Wi-Fi Protected Setup - device attributes + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "rom/ets_sys.h" + +#include "wpa/includes.h" +#include "wpa/common.h" +#include "wps/wps_i.h" +#include "wps/wps_dev_attr.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +int ICACHE_FLASH_ATTR wps_build_manufacturer(struct wps_device_data* dev, struct wpabuf* msg) +{ + size_t len; + wpa_printf(MSG_DEBUG, "WPS: * Manufacturer"); + wpabuf_put_be16(msg, ATTR_MANUFACTURER); + len = dev->manufacturer ? os_strlen(dev->manufacturer) : 0; +#ifndef CONFIG_WPS_STRICT + + if (len == 0) { + /* + * Some deployed WPS implementations fail to parse zero-length + * attributes. As a workaround, send a space character if the + * device attribute string is empty. + */ + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, ' '); + return 0; + } + +#endif /* CONFIG_WPS_STRICT */ + wpabuf_put_be16(msg, len); + wpabuf_put_data(msg, dev->manufacturer, len); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_model_name(struct wps_device_data* dev, struct wpabuf* msg) +{ + size_t len; + wpa_printf(MSG_DEBUG, "WPS: * Model Name"); + wpabuf_put_be16(msg, ATTR_MODEL_NAME); + len = dev->model_name ? os_strlen(dev->model_name) : 0; +#ifndef CONFIG_WPS_STRICT + + if (len == 0) { + /* + * Some deployed WPS implementations fail to parse zero-length + * attributes. As a workaround, send a space character if the + * device attribute string is empty. + */ + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, ' '); + return 0; + } + +#endif /* CONFIG_WPS_STRICT */ + wpabuf_put_be16(msg, len); + wpabuf_put_data(msg, dev->model_name, len); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_model_number(struct wps_device_data* dev, struct wpabuf* msg) +{ + size_t len; + wpa_printf(MSG_DEBUG, "WPS: * Model Number"); + wpabuf_put_be16(msg, ATTR_MODEL_NUMBER); + len = dev->model_number ? os_strlen(dev->model_number) : 0; +#ifndef CONFIG_WPS_STRICT + + if (len == 0) { + /* + * Some deployed WPS implementations fail to parse zero-length + * attributes. As a workaround, send a space character if the + * device attribute string is empty. + */ + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, ' '); + return 0; + } + +#endif /* CONFIG_WPS_STRICT */ + wpabuf_put_be16(msg, len); + wpabuf_put_data(msg, dev->model_number, len); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_serial_number(struct wps_device_data* dev, + struct wpabuf* msg) +{ + size_t len; + wpa_printf(MSG_DEBUG, "WPS: * Serial Number"); + wpabuf_put_be16(msg, ATTR_SERIAL_NUMBER); + len = dev->serial_number ? os_strlen(dev->serial_number) : 0; +#ifndef CONFIG_WPS_STRICT + + if (len == 0) { + /* + * Some deployed WPS implementations fail to parse zero-length + * attributes. As a workaround, send a space character if the + * device attribute string is empty. + */ + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, ' '); + return 0; + } + +#endif /* CONFIG_WPS_STRICT */ + wpabuf_put_be16(msg, len); + wpabuf_put_data(msg, dev->serial_number, len); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_primary_dev_type(struct wps_device_data* dev, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * Primary Device Type"); + wpabuf_put_be16(msg, ATTR_PRIMARY_DEV_TYPE); + wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN); + wpabuf_put_data(msg, dev->pri_dev_type, WPS_DEV_TYPE_LEN); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_secondary_dev_type(struct wps_device_data* dev, + struct wpabuf* msg) +{ + if (!dev->num_sec_dev_types) { + return 0; + } + + wpa_printf(MSG_DEBUG, "WPS: * Secondary Device Type"); + wpabuf_put_be16(msg, ATTR_SECONDARY_DEV_TYPE_LIST); + wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN * dev->num_sec_dev_types); + wpabuf_put_data(msg, dev->sec_dev_type, + WPS_DEV_TYPE_LEN * dev->num_sec_dev_types); + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_req_dev_type(struct wps_device_data* dev, struct wpabuf* msg, + unsigned int num_req_dev_types, + const u8* req_dev_types) +{ + unsigned int i; + + for (i = 0; i < num_req_dev_types; i++) { + wpa_hexdump(MSG_DEBUG, "WPS: * Requested Device Type", + req_dev_types + i * WPS_DEV_TYPE_LEN, + WPS_DEV_TYPE_LEN); + wpabuf_put_be16(msg, ATTR_REQUESTED_DEV_TYPE); + wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN); + wpabuf_put_data(msg, req_dev_types + i * WPS_DEV_TYPE_LEN, + WPS_DEV_TYPE_LEN); + } + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_dev_name(struct wps_device_data* dev, struct wpabuf* msg) +{ + size_t len; + wpa_printf(MSG_DEBUG, "WPS: * Device Name"); + wpabuf_put_be16(msg, ATTR_DEV_NAME); + len = dev->device_name ? os_strlen(dev->device_name) : 0; +#ifndef CONFIG_WPS_STRICT + + if (len == 0) { + /* + * Some deployed WPS implementations fail to parse zero-length + * attributes. As a workaround, send a space character if the + * device attribute string is empty. + */ + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, ' '); + return 0; + } + +#endif /* CONFIG_WPS_STRICT */ + wpabuf_put_be16(msg, len); + wpabuf_put_data(msg, dev->device_name, len); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_device_attrs(struct wps_device_data* dev, struct wpabuf* msg) +{ + if (wps_build_manufacturer(dev, msg) || + wps_build_model_name(dev, msg) || + wps_build_model_number(dev, msg) || + wps_build_serial_number(dev, msg) || + wps_build_primary_dev_type(dev, msg) || + wps_build_dev_name(dev, msg)) { + return -1; + } + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_os_version(struct wps_device_data* dev, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * OS Version"); + wpabuf_put_be16(msg, ATTR_OS_VERSION); + wpabuf_put_be16(msg, 4); + wpabuf_put_be32(msg, 0x80000000 | dev->os_version); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_vendor_ext_m1(struct wps_device_data* dev, struct wpabuf* msg) +{ + if (dev->vendor_ext_m1 != NULL) { + wpa_hexdump(MSG_DEBUG, "WPS: * Vendor Extension M1", + wpabuf_head_u8(dev->vendor_ext_m1), + wpabuf_len(dev->vendor_ext_m1)); + wpabuf_put_be16(msg, ATTR_VENDOR_EXT); + wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext_m1)); + wpabuf_put_buf(msg, dev->vendor_ext_m1); + } + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_rf_bands(struct wps_device_data* dev, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * RF Bands (%x)", dev->rf_bands); + wpabuf_put_be16(msg, ATTR_RF_BANDS); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, dev->rf_bands); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_vendor_ext(struct wps_device_data* dev, struct wpabuf* msg) +{ + int i; + + for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { + if (dev->vendor_ext[i] == NULL) { + continue; + } + + wpa_hexdump(MSG_DEBUG, "WPS: * Vendor Extension", + wpabuf_head_u8(dev->vendor_ext[i]), + wpabuf_len(dev->vendor_ext[i])); + wpabuf_put_be16(msg, ATTR_VENDOR_EXT); + wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext[i])); + wpabuf_put_buf(msg, dev->vendor_ext[i]); + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_manufacturer(struct wps_device_data* dev, const u8* str, + size_t str_len) +{ + if (str == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Manufacturer received"); + return -1; + } + + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", str, str_len); + + os_free(dev->manufacturer); + dev->manufacturer = (char*)os_malloc(str_len + 1); + + if (dev->manufacturer == NULL) { + return -1; + } + + os_memcpy(dev->manufacturer, str, str_len); + dev->manufacturer[str_len] = '\0'; + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_model_name(struct wps_device_data* dev, const u8* str, + size_t str_len) +{ + if (str == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Model Name received"); + return -1; + } + + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", str, str_len); + + os_free(dev->model_name); + dev->model_name = (char*)os_malloc(str_len + 1); + + if (dev->model_name == NULL) { + return -1; + } + + os_memcpy(dev->model_name, str, str_len); + dev->model_name[str_len] = '\0'; + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_model_number(struct wps_device_data* dev, const u8* str, + size_t str_len) +{ + if (str == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Model Number received"); + return -1; + } + + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", str, str_len); + + os_free(dev->model_number); + dev->model_number = (char*)os_malloc(str_len + 1); + + if (dev->model_number == NULL) { + return -1; + } + + os_memcpy(dev->model_number, str, str_len); + dev->model_number[str_len] = '\0'; + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_serial_number(struct wps_device_data* dev, + const u8* str, size_t str_len) +{ + if (str == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Serial Number received"); + return -1; + } + + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", str, str_len); + + os_free(dev->serial_number); + dev->serial_number = (char*)os_malloc(str_len + 1); + + if (dev->serial_number == NULL) { + return -1; + } + + os_memcpy(dev->serial_number, str, str_len); + dev->serial_number[str_len] = '\0'; + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_dev_name(struct wps_device_data* dev, const u8* str, + size_t str_len) +{ + if (str == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Device Name received"); + return -1; + } + + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", str, str_len); + + os_free(dev->device_name); + dev->device_name = (char*)os_malloc(str_len + 1); + + if (dev->device_name == NULL) { + return -1; + } + + os_memcpy(dev->device_name, str, str_len); + dev->device_name[str_len] = '\0'; + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_primary_dev_type(struct wps_device_data* dev, + const u8* dev_type) +{ +#if 0 +#ifndef CONFIG_NO_STDOUT_DEBUG + char devtype[WPS_DEV_TYPE_BUFSIZE]; +#endif /* CONFIG_NO_STDOUT_DEBUG */ +#endif + + if (dev_type == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Primary Device Type received"); + return -1; + } + + os_memcpy(dev->pri_dev_type, dev_type, WPS_DEV_TYPE_LEN); + //wpa_printf(MSG_DEBUG, "WPS: Primary Device Type: %s", + // wps_dev_type_bin2str(dev->pri_dev_type, devtype, + // sizeof(devtype))); + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_process_device_attrs(struct wps_device_data* dev, + struct wps_parse_attr* attr) +{ + if (wps_process_manufacturer(dev, attr->manufacturer, + attr->manufacturer_len) || + wps_process_model_name(dev, attr->model_name, + attr->model_name_len) || + wps_process_model_number(dev, attr->model_number, + attr->model_number_len) || + wps_process_serial_number(dev, attr->serial_number, + attr->serial_number_len) || + wps_process_primary_dev_type(dev, attr->primary_dev_type) || + wps_process_dev_name(dev, attr->dev_name, attr->dev_name_len)) { + return -1; + } + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_process_os_version(struct wps_device_data* dev, const u8* ver) +{ + if (ver == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No OS Version received"); + return -1; + } + + dev->os_version = WPA_GET_BE32(ver); + wpa_printf(MSG_DEBUG, "WPS: OS Version %08x", dev->os_version); + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_process_rf_bands(struct wps_device_data* dev, const u8* bands) +{ + if (bands == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No RF Bands received"); + return -1; + } + + dev->rf_bands = *bands; + wpa_printf(MSG_DEBUG, "WPS: Enrollee RF Bands 0x%x", dev->rf_bands); + + return 0; +} + + +void ICACHE_FLASH_ATTR wps_device_data_dup(struct wps_device_data* dst, + const struct wps_device_data* src) +{ + if (src->device_name) { + dst->device_name = os_strdup(src->device_name); + } + + if (src->manufacturer) { + dst->manufacturer = os_strdup(src->manufacturer); + } + + if (src->model_name) { + dst->model_name = os_strdup(src->model_name); + } + + if (src->model_number) { + dst->model_number = os_strdup(src->model_number); + } + + if (src->serial_number) { + dst->serial_number = os_strdup(src->serial_number); + } + + os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN); + dst->os_version = src->os_version; + dst->rf_bands = src->rf_bands; +} + + +void ICACHE_FLASH_ATTR wps_device_data_free(struct wps_device_data* dev) +{ + os_free(dev->device_name); + dev->device_name = NULL; + os_free(dev->manufacturer); + dev->manufacturer = NULL; + os_free(dev->model_name); + dev->model_name = NULL; + os_free(dev->model_number); + dev->model_number = NULL; + os_free(dev->serial_number); + dev->serial_number = NULL; +} diff --git a/components/wpa_supplicant/src/wps/wps_enrollee.c b/components/wpa_supplicant/src/wps/wps_enrollee.c new file mode 100644 index 00000000..760189db --- /dev/null +++ b/components/wpa_supplicant/src/wps/wps_enrollee.c @@ -0,0 +1,1713 @@ +/* + * Wi-Fi Protected Setup - Enrollee + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "rom/ets_sys.h" + +#include "wps/asm/irqflags.h" +#include "wpa/includes.h" +#include "wpa/common.h" +#include "wps/wps_i.h" +#include "wps/wps.h" +#include "wps/wps_dev_attr.h" + +#include "crypto/crypto.h" +#include "crypto/sha256.h" +#include "crypto/random.h" + +//#include "pp/mac_register_v6.h" + +#include "esp_wifi_osi.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +#define API_MUTEX_DECLARE(t) local_irq_declare(t) +#define API_MUTEX_TAKE(t) local_irq_save(t) +#define API_MUTEX_GIVE(t) local_irq_restore(t) + +extern struct wps_sm* gWpsSm; + +extern bool system_overclock(void); +extern bool system_restoreclock(void); + +static int ICACHE_FLASH_ATTR wps_build_mac_addr(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * MAC Address"); + wpabuf_put_be16(msg, ATTR_MAC_ADDR); + wpabuf_put_be16(msg, ETH_ALEN); + wpabuf_put_data(msg, wps->mac_addr_e, ETH_ALEN); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_wps_state(struct wps_data* wps, struct wpabuf* msg) +{ + u8 state; + + if (wps->wps->ap) { + state = wps->wps->wps_state; + } else { + state = WPS_STATE_NOT_CONFIGURED; + } + + wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)", + state); + wpabuf_put_be16(msg, ATTR_WPS_STATE); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, state); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_e_hash(struct wps_data* wps, struct wpabuf* msg) +{ + u8* hash; + const u8* addr[4]; + size_t len[4]; + + if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0) { + return -1; + } + + wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: E-S2", + wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN); + + if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) { + wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for " + "E-Hash derivation"); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: * E-Hash1"); + wpabuf_put_be16(msg, ATTR_E_HASH1); + wpabuf_put_be16(msg, SHA256_MAC_LEN); + hash = wpabuf_put(msg, SHA256_MAC_LEN); + /* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */ + addr[0] = wps->snonce; + len[0] = WPS_SECRET_NONCE_LEN; + addr[1] = wps->psk1; + len[1] = WPS_PSK_LEN; + addr[2] = wpabuf_head(wps->dh_pubkey_e); + len[2] = wpabuf_len(wps->dh_pubkey_e); + addr[3] = wpabuf_head(wps->dh_pubkey_r); + len[3] = wpabuf_len(wps->dh_pubkey_r); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN); + + wpa_printf(MSG_DEBUG, "WPS: * E-Hash2"); + wpabuf_put_be16(msg, ATTR_E_HASH2); + wpabuf_put_be16(msg, SHA256_MAC_LEN); + hash = wpabuf_put(msg, SHA256_MAC_LEN); + /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */ + addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; + addr[1] = wps->psk2; + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_e_snonce1(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * E-SNonce1"); + wpabuf_put_be16(msg, ATTR_E_SNONCE1); + wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); + wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_e_snonce2(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * E-SNonce2"); + wpabuf_put_be16(msg, ATTR_E_SNONCE2); + wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); + wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN, + WPS_SECRET_NONCE_LEN); + return 0; +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_m1(struct wps_data* wps) +{ + struct wpabuf* msg; + u16 config_methods; + + if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0) { + return NULL; + } + + wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce", + wps->nonce_e, WPS_NONCE_LEN); + + wpa_printf(MSG_DEBUG, "WPS: Building Message M1"); + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + return NULL; + } + + config_methods = wps->wps->config_methods; + + if (wps->wps->ap && !wps->pbc_in_m1 && + (wps->dev_password_len != 0 || + (config_methods & WPS_CONFIG_DISPLAY))) { + /* + * These are the methods that the AP supports as an Enrollee + * for adding external Registrars, so remove PushButton. + * + * As a workaround for Windows 7 mechanism for probing WPS + * capabilities from M1, leave PushButton option if no PIN + * method is available or if WPS configuration enables PBC + * workaround. + */ + config_methods &= ~WPS_CONFIG_PUSHBUTTON; +#ifdef CONFIG_WPS2 + config_methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | + WPS_CONFIG_PHY_PUSHBUTTON); +#endif /* CONFIG_WPS2 */ + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_M1) || + wps_build_uuid_e(msg, wps->uuid_e) || + wps_build_mac_addr(wps, msg) || + wps_build_enrollee_nonce(wps, msg) || + wps_build_public_key(wps, msg, WPS_CALC_KEY_NO_CALC) || + wps_build_auth_type_flags(wps, msg) || + wps_build_encr_type_flags(wps, msg) || + wps_build_conn_type_flags(wps, msg) || + wps_build_config_methods(msg, config_methods) || + wps_build_wps_state(wps, msg) || + wps_build_device_attrs(&wps->wps->dev, msg) || + wps_build_rf_bands(&wps->wps->dev, msg) || + wps_build_assoc_state(wps, msg) || + wps_build_dev_password_id(msg, wps->dev_pw_id) || + wps_build_config_error(msg, WPS_CFG_NO_ERROR) || + wps_build_os_version(&wps->wps->dev, msg) || + wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_vendor_ext_m1(&wps->wps->dev, msg)) { + wpabuf_free(msg); + return NULL; + } + + wps->state = RECV_M2; + return msg; +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_m3(struct wps_data* wps) +{ + struct wpabuf* msg; + + wpa_printf(MSG_DEBUG, "WPS: Building Message M3"); + + if (wps->dev_password == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Device Password available"); + return NULL; + } + + wps_derive_psk(wps, wps->dev_password, wps->dev_password_len); + + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + return NULL; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_M3) || + wps_build_registrar_nonce(wps, msg) || + wps_build_e_hash(wps, msg) || + wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_authenticator(wps, msg)) { + wpabuf_free(msg); + return NULL; + } + + wps->state = RECV_M4; + return msg; +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_m5(struct wps_data* wps) +{ + struct wpabuf* msg, *plain; + + wpa_printf(MSG_DEBUG, "WPS: Building Message M5"); + + plain = wpabuf_alloc(200); + + if (plain == NULL) { + return NULL; + } + + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + wpabuf_free(plain); + return NULL; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_M5) || + wps_build_registrar_nonce(wps, msg) || + wps_build_e_snonce1(wps, plain) || + wps_build_key_wrap_auth(wps, plain) || + wps_build_encr_settings(wps, msg, plain) || + wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_authenticator(wps, msg)) { + wpabuf_free(plain); + wpabuf_free(msg); + return NULL; + } + + wpabuf_free(plain); + + wps->state = RECV_M6; + return msg; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_ssid(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * SSID"); + wpabuf_put_be16(msg, ATTR_SSID); + wpabuf_put_be16(msg, wps->wps->ssid_len); + wpabuf_put_data(msg, wps->wps->ssid, wps->wps->ssid_len); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_auth_type(struct wps_data* wps, struct wpabuf* msg) +{ + u16 auth_type = wps->wps->auth_types; + + /* Select the best authentication type */ + if (auth_type & WPS_AUTH_WPA2PSK) { + auth_type = WPS_AUTH_WPA2PSK; + } else if (auth_type & WPS_AUTH_WPAPSK) { + auth_type = WPS_AUTH_WPAPSK; + } else if (auth_type & WPS_AUTH_OPEN) { + auth_type = WPS_AUTH_OPEN; + } else if (auth_type & WPS_AUTH_SHARED) { + auth_type = WPS_AUTH_SHARED; + } + + wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)", auth_type); + wpabuf_put_be16(msg, ATTR_AUTH_TYPE); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, auth_type); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_encr_type(struct wps_data* wps, struct wpabuf* msg) +{ + u16 encr_type = wps->wps->encr_types; + + /* Select the best encryption type */ + if (wps->wps->auth_types & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) { + if (encr_type & WPS_ENCR_AES) { + encr_type = WPS_ENCR_AES; + } else if (encr_type & WPS_ENCR_TKIP) { + encr_type = WPS_ENCR_TKIP; + } + } else { + if (encr_type & WPS_ENCR_WEP) { + encr_type = WPS_ENCR_WEP; + } else if (encr_type & WPS_ENCR_NONE) { + encr_type = WPS_ENCR_NONE; + } + } + + wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)", encr_type); + wpabuf_put_be16(msg, ATTR_ENCR_TYPE); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, encr_type); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_network_key(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * Network Key"); + wpabuf_put_be16(msg, ATTR_NETWORK_KEY); + wpabuf_put_be16(msg, wps->wps->network_key_len); + wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_mac_addr(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * MAC Address (AP BSSID)"); + wpabuf_put_be16(msg, ATTR_MAC_ADDR); + wpabuf_put_be16(msg, ETH_ALEN); + wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_ap_settings(struct wps_data* wps, struct wpabuf* plain) +{ + if (wps->wps->ap_settings) { + wpa_printf(MSG_DEBUG, "WPS: * AP Settings (pre-configured)"); + wpabuf_put_data(plain, wps->wps->ap_settings, + wps->wps->ap_settings_len); + return 0; + } + + return wps_build_cred_ssid(wps, plain) || + wps_build_cred_mac_addr(wps, plain) || + wps_build_cred_auth_type(wps, plain) || + wps_build_cred_encr_type(wps, plain) || + wps_build_cred_network_key(wps, plain); +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_m7(struct wps_data* wps) +{ + struct wpabuf* msg, *plain; + + wpa_printf(MSG_DEBUG, "WPS: Building Message M7"); + + plain = wpabuf_alloc(500 + wps->wps->ap_settings_len); + + if (plain == NULL) { + return NULL; + } + + msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len); + + if (msg == NULL) { + wpabuf_free(plain); + return NULL; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_M7) || + wps_build_registrar_nonce(wps, msg) || + wps_build_e_snonce2(wps, plain) || + (wps->wps->ap && wps_build_ap_settings(wps, plain)) || + wps_build_key_wrap_auth(wps, plain) || + wps_build_encr_settings(wps, msg, plain) || + wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_authenticator(wps, msg)) { + wpabuf_free(plain); + wpabuf_free(msg); + return NULL; + } + + wpabuf_free(plain); + + if (wps->wps->ap && wps->wps->registrar) { + /* + * If the Registrar is only learning our current configuration, + * it may not continue protocol run to successful completion. + * Store information here to make sure it remains available. + */ + wps_device_store(wps->wps->registrar, &wps->peer_dev, + wps->uuid_r); + } + + wps->state = RECV_M8; + return msg; +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_wsc_done(struct wps_data* wps) +{ + struct wpabuf* msg; + + wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_Done"); + + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + return NULL; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_WSC_DONE) || + wps_build_enrollee_nonce(wps, msg) || + wps_build_registrar_nonce(wps, msg) || + wps_build_wfa_ext(msg, 0, NULL, 0)) { + wpabuf_free(msg); + return NULL; + } + + if (wps->wps->ap) { + wps->state = RECV_ACK; + } else { + wps_success_event(wps->wps); + wps->state = WPS_FINISHED; + } + + return msg; +} + + +struct wpabuf* ICACHE_FLASH_ATTR wps_enrollee_get_msg(struct wps_data* wps, + enum wsc_op_code* op_code) +{ + struct wpabuf* msg; + + switch (wps->state) { + case SEND_M1: + msg = wps_build_m1(wps); + *op_code = WSC_MSG; + break; + + case SEND_M3: + msg = wps_build_m3(wps); + *op_code = WSC_MSG; + break; + + case SEND_M5: + msg = wps_build_m5(wps); + *op_code = WSC_MSG; + break; + + case SEND_M7: + msg = wps_build_m7(wps); + *op_code = WSC_MSG; + break; + + case RECEIVED_M2D: + if (wps->wps->ap) { + msg = wps_build_wsc_nack(wps); + *op_code = WSC_NACK; + break; + } + + msg = wps_build_wsc_ack(wps); + *op_code = WSC_ACK; + + if (msg) { + /* Another M2/M2D may be received */ + wps->state = RECV_M2; + } + + break; + + case SEND_WSC_NACK: + msg = wps_build_wsc_nack(wps); + *op_code = WSC_NACK; + break; + + case WPS_MSG_DONE: + msg = wps_build_wsc_done(wps); + *op_code = WSC_Done; + break; + + default: + wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building " + "a message", wps->state); + msg = NULL; + break; + } + + if (*op_code == WSC_MSG && msg) { + /* Save a copy of the last message for Authenticator derivation + */ + wpabuf_free(wps->last_msg); + wps->last_msg = wpabuf_dup(msg); + } + + return msg; +} + + +static int ICACHE_FLASH_ATTR wps_process_registrar_nonce(struct wps_data* wps, const u8* r_nonce) +{ + if (r_nonce == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received"); + return -1; + } + + os_memcpy(wps->nonce_r, r_nonce, WPS_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce", + wps->nonce_r, WPS_NONCE_LEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_enrollee_nonce(struct wps_data* wps, const u8* e_nonce) +{ + if (e_nonce == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received"); + return -1; + } + + if (os_memcmp(wps->nonce_e, e_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce received"); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_uuid_r(struct wps_data* wps, const u8* uuid_r) +{ + if (uuid_r == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No UUID-R received"); + return -1; + } + + os_memcpy(wps->uuid_r, uuid_r, WPS_UUID_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_pubkey(struct wps_data* wps, const u8* pk, + size_t pk_len) +{ + if (pk == NULL || pk_len == 0) { + wpa_printf(MSG_DEBUG, "WPS: No Public Key received"); + return -1; + } + + wpabuf_free(wps->dh_pubkey_r); + wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len); + + if (wps->dh_pubkey_r == NULL) { + return -1; + } + + wpa_printf(MSG_DEBUG, "process pubkey start"); + API_MUTEX_DECLARE(c_tmp); + API_MUTEX_TAKE(c_tmp); + //pp_soft_wdt_stop(); + + //REG_SET_BIT(0x3ff00014, BIT(0)); //change CPU to 160Mhz + //ets_update_cpu_frequency(160); + //printf("[%s]line:[%d]%d\r\n", __func__, __LINE__, REG_READ(0x3ff20c00)); + system_overclock(); + + if (wps_derive_keys(wps) < 0) { + //REG_CLR_BIT(0x3ff00014, BIT(0)); //change CPU to 80Mhz + //ets_update_cpu_frequency(80); + system_restoreclock(); + //pp_soft_wdt_restart(); + API_MUTEX_GIVE(c_tmp); + return -1; + } + + system_restoreclock(); + //printf("[%s]line:[%d]%d\r\n", __func__, __LINE__, REG_READ(0x3ff20c00)); + //REG_CLR_BIT(0x3ff00014, BIT(0)); //change CPU to 80Mhz + //ets_update_cpu_frequency(80); + + //pp_soft_wdt_restart(); + API_MUTEX_GIVE(c_tmp); + + wpa_printf(MSG_DEBUG, "process pubkey finish"); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_r_hash1(struct wps_data* wps, const u8* r_hash1) +{ + if (r_hash1 == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No R-Hash1 received"); + return -1; + } + + os_memcpy(wps->peer_hash1, r_hash1, WPS_HASH_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", wps->peer_hash1, WPS_HASH_LEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_r_hash2(struct wps_data* wps, const u8* r_hash2) +{ + if (r_hash2 == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No R-Hash2 received"); + return -1; + } + + os_memcpy(wps->peer_hash2, r_hash2, WPS_HASH_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", wps->peer_hash2, WPS_HASH_LEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_r_snonce1(struct wps_data* wps, const u8* r_snonce1) +{ + u8 hash[SHA256_MAC_LEN]; + const u8* addr[4]; + size_t len[4]; + + if (r_snonce1 == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No R-SNonce1 received"); + return -1; + } + + wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce1", r_snonce1, + WPS_SECRET_NONCE_LEN); + + /* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */ + addr[0] = r_snonce1; + len[0] = WPS_SECRET_NONCE_LEN; + addr[1] = wps->psk1; + len[1] = WPS_PSK_LEN; + addr[2] = wpabuf_head(wps->dh_pubkey_e); + len[2] = wpabuf_len(wps->dh_pubkey_e); + addr[3] = wpabuf_head(wps->dh_pubkey_r); + len[3] = wpabuf_len(wps->dh_pubkey_r); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + + if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does " + "not match with the pre-committed value"); + wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; + wps_pwd_auth_fail_event(wps->wps, 1, 1); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the first " + "half of the device password"); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_r_snonce2(struct wps_data* wps, const u8* r_snonce2) +{ + u8 hash[SHA256_MAC_LEN]; + const u8* addr[4]; + size_t len[4]; + + if (r_snonce2 == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received"); + return -1; + } + + wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2, + WPS_SECRET_NONCE_LEN); + + /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */ + addr[0] = r_snonce2; + len[0] = WPS_SECRET_NONCE_LEN; + addr[1] = wps->psk2; + len[1] = WPS_PSK_LEN; + addr[2] = wpabuf_head(wps->dh_pubkey_e); + len[2] = wpabuf_len(wps->dh_pubkey_e); + addr[3] = wpabuf_head(wps->dh_pubkey_r); + len[3] = wpabuf_len(wps->dh_pubkey_r); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + + if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does " + "not match with the pre-committed value"); + wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; + wps_pwd_auth_fail_event(wps->wps, 1, 2); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second " + "half of the device password"); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_cred_e(struct wps_data* wps, const u8* cred, + size_t cred_len, int wps2) +{ + struct wps_parse_attr* attr; + struct wpabuf msg; + int ret = 0; + + wpa_printf(MSG_DEBUG, "WPS: Received Credential"); + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + return -99; + } + + os_memset(&wps->cred, 0, sizeof(wps->cred)); + wpabuf_set(&msg, cred, cred_len); + + if (wps_parse_msg(&msg, attr) < 0 || + wps_process_cred(attr, &wps->cred)) { + ret = -1; + goto _out; + } + + if (os_memcmp(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) != + 0) { + wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential (" + MACSTR ") does not match with own address (" MACSTR + ")", MAC2STR(wps->cred.mac_addr), + MAC2STR(wps->wps->dev.mac_addr)); + /* + * In theory, this could be consider fatal error, but there are + * number of deployed implementations using other address here + * due to unclarity in the specification. For interoperability + * reasons, allow this to be processed since we do not really + * use the MAC Address information for anything. + */ +#ifdef CONFIG_WPS_STRICT + + if (wps2) { + wpa_printf(MSG_INFO, "WPS: Do not accept incorrect " + "MAC Address in AP Settings"); + ret = -1; + goto _out; + } + +#endif /* CONFIG_WPS_STRICT */ + } + +#ifdef CONFIG_WPS2 + + if (!(wps->cred.encr_type & + (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) { + if (wps->cred.encr_type & WPS_ENCR_WEP) { + wpa_printf(MSG_INFO, "WPS: Reject Credential " + "due to WEP configuration"); + wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED; + ret = -2; + goto _out; + } + + wpa_printf(MSG_INFO, "WPS: Reject Credential due to " + "invalid encr_type 0x%x", wps->cred.encr_type); + ret = -1; + goto _out; + } + +#endif /* CONFIG_WPS2 */ + + wps_ssid_save(wps->cred.ssid, wps->cred.ssid_len); + wps_key_save((char*)wps->cred.key, wps->cred.key_len); + + if (wps->wps->cred_cb) { + wps->cred.cred_attr = cred - 4; + wps->cred.cred_attr_len = cred_len + 4; + ret = wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred); + wps->cred.cred_attr = NULL; + wps->cred.cred_attr_len = 0; + } + +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +static int ICACHE_FLASH_ATTR wps_process_creds(struct wps_data* wps, const u8* cred[], + size_t cred_len[], size_t num_cred, int wps2) +{ + size_t i; + int ok = 0; + + if (wps->wps->ap) { + return 0; + } + + if (num_cred == 0) { + wpa_printf(MSG_DEBUG, "WPS: No Credential attributes " + "received"); + return -1; + } + + for (i = 0; i < num_cred; i++) { + int res; + res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2); + + if (res == 0) { + ok++; + } else if (res == -2) { + wpa_printf(MSG_DEBUG, "WPS: WEP credential skipped"); + } else { + return -1; + } + } + + if (ok == 0) { + wpa_printf(MSG_DEBUG, "WPS: No valid Credential attribute " + "received"); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_ap_settings_e(struct wps_data* wps, + struct wps_parse_attr* attr, + struct wpabuf* attrs, int wps2) +{ + struct wps_credential* cred; + int ret = 0; + + cred = (struct wps_credential*)os_zalloc(sizeof(struct wps_credential)); + + if (cred == NULL) { + ret = -99; + goto _out; + } + + if (!wps->wps->ap) { + ret = 0; + goto _out; + } + + if (wps_process_ap_settings(attr, cred) < 0) { + ret = -1; + goto _out; + } + + wpa_printf(MSG_INFO, "WPS: Received new AP configuration from " + "Registrar"); + + if (os_memcmp(cred->mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) != + 0) { + wpa_printf(MSG_DEBUG, "WPS: MAC Address in the AP Settings (" + MACSTR ") does not match with own address (" MACSTR + ")", MAC2STR(cred->mac_addr), + MAC2STR(wps->wps->dev.mac_addr)); + /* + * In theory, this could be consider fatal error, but there are + * number of deployed implementations using other address here + * due to unclarity in the specification. For interoperability + * reasons, allow this to be processed since we do not really + * use the MAC Address information for anything. + */ +#ifdef CONFIG_WPS_STRICT + + if (wps2) { + wpa_printf(MSG_INFO, "WPS: Do not accept incorrect " + "MAC Address in AP Settings"); + ret = -1; + goto _out; + } + +#endif /* CONFIG_WPS_STRICT */ + } + +#ifdef CONFIG_WPS2 + + if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) { + if (cred->encr_type & WPS_ENCR_WEP) { + wpa_printf(MSG_INFO, "WPS: Reject new AP settings " + "due to WEP configuration"); + wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED; + ret = -1; + goto _out; + } + + wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to " + "invalid encr_type 0x%x", cred->encr_type); + ret = -1; + goto _out; + } + +#endif /* CONFIG_WPS2 */ + +#ifdef CONFIG_WPS_STRICT + + if (wps2) { + if ((cred->encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == + WPS_ENCR_TKIP || + (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == + WPS_AUTH_WPAPSK) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC 2.0 " + "AP Settings: WPA-Personal/TKIP only"); + wps->error_indication = + WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED; + ret = -1; + goto _out; + } + } + +#endif /* CONFIG_WPS_STRICT */ + +#ifdef CONFIG_WPS2 + + if ((cred->encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == WPS_ENCR_TKIP) { + wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> " + "TKIP+AES"); + cred->encr_type |= WPS_ENCR_AES; + } + + if ((cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == + WPS_AUTH_WPAPSK) { + wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> " + "WPAPSK+WPA2PSK"); + cred->auth_type |= WPS_AUTH_WPA2PSK; + } + +#endif /* CONFIG_WPS2 */ + + if (wps->wps->cred_cb) { + cred->cred_attr = wpabuf_head(attrs); + cred->cred_attr_len = wpabuf_len(attrs); + wps->wps->cred_cb(wps->wps->cb_ctx, cred); + } + +_out: + + if (cred) { + os_free(cred); + } + + return ret; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_m2(struct wps_data* wps, + const struct wpabuf* msg, + struct wps_parse_attr* attr) +{ + wpa_printf(MSG_DEBUG, "WPS: Received M2"); + + if (wps->state != RECV_M2) { + wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " + "receiving M2", wps->state); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + if (wps_process_registrar_nonce(wps, attr->registrar_nonce) || + wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || + wps_process_uuid_r(wps, attr->uuid_r)) { + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + /* + * Stop here on an AP as an Enrollee if AP Setup is locked unless the + * special locked mode is used to allow protocol run up to M7 in order + * to support external Registrars that only learn the current AP + * configuration without changing it. + */ + if (wps->wps->ap && + ((wps->wps->ap_setup_locked && wps->wps->ap_setup_locked != 2) || + wps->dev_password == NULL)) { + wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse " + "registration of a new Registrar"); + wps->config_error = WPS_CFG_SETUP_LOCKED; + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + if (wps_process_pubkey(wps, attr->public_key, attr->public_key_len) || + wps_process_authenticator(wps, attr->authenticator, msg) || + wps_process_device_attrs(&wps->peer_dev, attr)) { + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + wps->state = SEND_M3; + return WPS_CONTINUE; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_m2d(struct wps_data* wps, + struct wps_parse_attr* attr) +{ + wpa_printf(MSG_DEBUG, "WPS: Received M2D"); + + if (wps->state != RECV_M2) { + wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " + "receiving M2D", wps->state); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", + attr->manufacturer, attr->manufacturer_len); + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", + attr->model_name, attr->model_name_len); + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", + attr->model_number, attr->model_number_len); + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", + attr->serial_number, attr->serial_number_len); + wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", + attr->dev_name, attr->dev_name_len); + + if (wps->wps->event_cb) { + union wps_event_data data; + struct wps_event_m2d* m2d = &data.m2d; + os_memset(&data, 0, sizeof(data)); + + if (attr->config_methods) + m2d->config_methods = + WPA_GET_BE16(attr->config_methods); + + m2d->manufacturer = attr->manufacturer; + m2d->manufacturer_len = attr->manufacturer_len; + m2d->model_name = attr->model_name; + m2d->model_name_len = attr->model_name_len; + m2d->model_number = attr->model_number; + m2d->model_number_len = attr->model_number_len; + m2d->serial_number = attr->serial_number; + m2d->serial_number_len = attr->serial_number_len; + m2d->dev_name = attr->dev_name; + m2d->dev_name_len = attr->dev_name_len; + m2d->primary_dev_type = attr->primary_dev_type; + + if (attr->config_error) + m2d->config_error = + WPA_GET_BE16(attr->config_error); + + if (attr->dev_password_id) + m2d->dev_password_id = + WPA_GET_BE16(attr->dev_password_id); + + wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_M2D, &data); + } + + wps->state = RECEIVED_M2D; + return WPS_CONTINUE; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_m4(struct wps_data* wps, + const struct wpabuf* msg, + struct wps_parse_attr* attr) +{ + struct wpabuf* decrypted; + struct wps_parse_attr* eattr; + enum wps_process_res res; + + wpa_printf(MSG_DEBUG, "WPS: Received M4"); + + eattr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (eattr == NULL) { + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + if (wps->state != RECV_M4) { + wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " + "receiving M4", wps->state); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || + wps_process_authenticator(wps, attr->authenticator, msg) || + wps_process_r_hash1(wps, attr->r_hash1) || + wps_process_r_hash2(wps, attr->r_hash2)) { + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, + attr->encr_settings_len); + + if (decrypted == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " + "Settings attribute"); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) { + wpabuf_free(decrypted); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " + "attribute"); + + if (wps_parse_msg(decrypted, eattr) < 0 || + wps_process_key_wrap_auth(wps, decrypted, eattr->key_wrap_auth) || + wps_process_r_snonce1(wps, eattr->r_snonce1)) { + wpabuf_free(decrypted); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + wpabuf_free(decrypted); + + wps->state = SEND_M5; + res = WPS_CONTINUE; +_out: + + if (eattr) { + os_free(eattr); + } + + return res; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_m6(struct wps_data* wps, + const struct wpabuf* msg, + struct wps_parse_attr* attr) +{ + struct wpabuf* decrypted; + struct wps_parse_attr* eattr; + enum wps_process_res res; + + wpa_printf(MSG_DEBUG, "WPS: Received M6"); + + eattr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (eattr == NULL) { + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + if (wps->state != RECV_M6) { + wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " + "receiving M6", wps->state); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || + wps_process_authenticator(wps, attr->authenticator, msg)) { + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, + attr->encr_settings_len); + + if (decrypted == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " + "Settings attribute"); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) { + wpabuf_free(decrypted); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " + "attribute"); + + if (wps_parse_msg(decrypted, eattr) < 0 || + wps_process_key_wrap_auth(wps, decrypted, eattr->key_wrap_auth) || + wps_process_r_snonce2(wps, eattr->r_snonce2)) { + wpabuf_free(decrypted); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + wpabuf_free(decrypted); + + if (wps->wps->ap) + wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS, + NULL); + + wps->state = SEND_M7; + res = WPS_CONTINUE; +_out: + + if (eattr) { + os_free(eattr); + } + + return res; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_m8(struct wps_data* wps, + const struct wpabuf* msg, + struct wps_parse_attr* attr) +{ + struct wpabuf* decrypted; + struct wps_parse_attr* eattr; + enum wps_process_res res; + + wpa_printf(MSG_DEBUG, "WPS: Received M8"); + + eattr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (eattr == NULL) { + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + if (wps->state != RECV_M8) { + wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " + "receiving M8", wps->state); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || + wps_process_authenticator(wps, attr->authenticator, msg)) { + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + if (wps->wps->ap && wps->wps->ap_setup_locked) { + /* + * Stop here if special ap_setup_locked == 2 mode allowed the + * protocol to continue beyond M2. This allows ER to learn the + * current AP settings without changing them. + */ + wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse " + "registration of a new Registrar"); + wps->config_error = WPS_CFG_SETUP_LOCKED; + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, + attr->encr_settings_len); + + if (decrypted == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " + "Settings attribute"); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + if (wps_validate_m8_encr(decrypted, wps->wps->ap, + attr->version2 != NULL) < 0) { + wpabuf_free(decrypted); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " + "attribute"); + + if (wps_parse_msg(decrypted, eattr) < 0 || + wps_process_key_wrap_auth(wps, decrypted, eattr->key_wrap_auth) || + wps_process_creds(wps, eattr->cred, eattr->cred_len, + eattr->num_cred, attr->version2 != NULL) || + wps_process_ap_settings_e(wps, eattr, decrypted, + attr->version2 != NULL)) { + wpabuf_free(decrypted); + wps->state = SEND_WSC_NACK; + res = WPS_CONTINUE; + goto _out; + } + + wpabuf_free(decrypted); + + wps->state = WPS_MSG_DONE; + res = WPS_CONTINUE; + +_out: + + if (eattr) { + os_free(eattr); + } + + return res; +} + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_wsc_start(struct wps_data* wps, + const struct wpabuf* msg) +{ + struct wps_sm* sm = gWpsSm; + enum wps_process_res ret = WPS_CONTINUE; + + wpa_printf(MSG_DEBUG, "WPS: Received WSC_START"); + os_timer_disarm(&sm->wps_eapol_start_timer); + wps->state = SEND_M1; + return ret; +} + +#define WPS_IGNORE_STATE(wps_st) do {\ + if (wps->state <= RECV_M8 && ((wps_st) == wps->state - 1 || (wps_st) == wps->state - 2)) { \ + return WPS_IGNORE;\ + }\ + } while (0) + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_wsc_msg(struct wps_data* wps, + const struct wpabuf* msg) +{ + struct wps_parse_attr* attr; + enum wps_process_res ret = WPS_CONTINUE; + + wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG"); + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = WPS_FAILURE; + goto _out; + } + + if (wps_parse_msg(msg, attr) < 0) { + ret = WPS_FAILURE; + goto _out; + } + + if (attr->enrollee_nonce == NULL || + os_memcmp(wps->nonce_e, attr->enrollee_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); + ret = WPS_FAILURE; + goto _out; + } + + if (attr->msg_type == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); + wps->state = SEND_WSC_NACK; + ret = WPS_CONTINUE; + goto _out; + } + + switch (*attr->msg_type) { + case WPS_M2: + WPS_IGNORE_STATE(RECV_M2); + + if (wps_validate_m2(msg) < 0) { + ret = WPS_FAILURE; + goto _out; + } + + ret = wps_process_m2(wps, msg, attr); + break; + + case WPS_M2D: + if (wps_validate_m2d(msg) < 0) { + ret = WPS_FAILURE; + goto _out; + } + + ret = wps_process_m2d(wps, attr); + break; + + case WPS_M4: + WPS_IGNORE_STATE(RECV_M4); + + if (wps_validate_m4(msg) < 0) { + ret = WPS_FAILURE; + goto _out; + } + + ret = wps_process_m4(wps, msg, attr); + + if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) + wps_fail_event(wps->wps, WPS_M4, wps->config_error, + wps->error_indication); + + break; + + case WPS_M6: + WPS_IGNORE_STATE(RECV_M6); + + if (wps_validate_m6(msg) < 0) { + ret = WPS_FAILURE; + goto _out; + } + + ret = wps_process_m6(wps, msg, attr); + + if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) + wps_fail_event(wps->wps, WPS_M6, wps->config_error, + wps->error_indication); + + break; + + case WPS_M8: + WPS_IGNORE_STATE(RECV_M8); + + if (wps_validate_m8(msg) < 0) { + ret = WPS_FAILURE; + goto _out; + } + + ret = wps_process_m8(wps, msg, attr); + + if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) + wps_fail_event(wps->wps, WPS_M8, wps->config_error, + wps->error_indication); + + break; + + default: + wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d", + *attr->msg_type); + ret = WPS_FAILURE; + goto _out; + } + + /* + * Save a copy of the last message for Authenticator derivation if we + * are continuing. However, skip M2D since it is not authenticated and + * neither is the ACK/NACK response frame. This allows the possibly + * following M2 to be processed correctly by using the previously sent + * M1 in Authenticator derivation. + */ + if (ret == WPS_CONTINUE && *attr->msg_type != WPS_M2D) { + /* Save a copy of the last message for Authenticator derivation + */ + wpabuf_free(wps->last_msg); + wps->last_msg = wpabuf_dup(msg); + } + +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_wsc_ack(struct wps_data* wps, + const struct wpabuf* msg) +{ + struct wps_parse_attr* attr; + enum wps_process_res res; + + wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK"); + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + res = WPS_FAILURE; + goto _out; + } + + if (wps_parse_msg(msg, attr) < 0) { + res = WPS_FAILURE; + goto _out; + } + + if (attr->msg_type == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); + res = WPS_FAILURE; + goto _out; + } + + if (*attr->msg_type != WPS_WSC_ACK) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", + *attr->msg_type); + res = WPS_FAILURE; + goto _out; + } + + if (attr->registrar_nonce == NULL || + os_memcmp(wps->nonce_r, attr->registrar_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); + res = WPS_FAILURE; + goto _out; + } + + if (attr->enrollee_nonce == NULL || + os_memcmp(wps->nonce_e, attr->enrollee_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); + res = WPS_FAILURE; + goto _out; + } + + if (wps->state == RECV_ACK && wps->wps->ap) { + wpa_printf(MSG_DEBUG, "WPS: External Registrar registration " + "completed successfully"); + wps_success_event(wps->wps); + wps->state = WPS_FINISHED; + res = WPS_DONE; + goto _out; + } + + res = WPS_FAILURE; +_out: + + if (attr) { + os_free(attr); + } + + return res; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_wsc_nack(struct wps_data* wps, + const struct wpabuf* msg) +{ + struct wps_parse_attr* attr; + enum wps_process_res res; + u16 config_error; + + wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK"); + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + res = WPS_FAILURE; + goto _out; + } + + if (wps_parse_msg(msg, attr) < 0) { + res = WPS_FAILURE; + goto _out; + } + + if (attr->msg_type == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); + res = WPS_FAILURE; + goto _out; + } + + if (*attr->msg_type != WPS_WSC_NACK) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", + *attr->msg_type); + res = WPS_FAILURE; + goto _out; + } + + if (attr->registrar_nonce == NULL || + os_memcmp(wps->nonce_r, attr->registrar_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); + wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce", + attr->registrar_nonce, WPS_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce", + wps->nonce_r, WPS_NONCE_LEN); + res = WPS_FAILURE; + goto _out; + } + + if (attr->enrollee_nonce == NULL || + os_memcmp(wps->nonce_e, attr->enrollee_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); + wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce", + attr->enrollee_nonce, WPS_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce", + wps->nonce_e, WPS_NONCE_LEN); + res = WPS_FAILURE; + goto _out; + } + + if (attr->config_error == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute " + "in WSC_NACK"); + res = WPS_FAILURE; + goto _out; + } + + config_error = WPA_GET_BE16(attr->config_error); + wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with " + "Configuration Error %d", config_error); + + switch (wps->state) { + case RECV_M4: + wps_fail_event(wps->wps, WPS_M3, config_error, + wps->error_indication); + break; + + case RECV_M6: + wps_fail_event(wps->wps, WPS_M5, config_error, + wps->error_indication); + break; + + case RECV_M8: + wps_fail_event(wps->wps, WPS_M7, config_error, + wps->error_indication); + break; + + default: + break; + } + + /* Followed by NACK if Enrollee is Supplicant or EAP-Failure if + * Enrollee is Authenticator */ + wps->state = SEND_WSC_NACK; + + res = WPS_FAILURE; +_out: + + if (attr) { + os_free(attr); + } + + return res; +} + + +enum wps_process_res ICACHE_FLASH_ATTR wps_enrollee_process_msg(struct wps_data* wps, + enum wsc_op_code op_code, + const struct wpabuf* msg) +{ + + wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu " + "op_code=%d)", + (unsigned long) wpabuf_len(msg), op_code); + + if (op_code == WSC_UPnP) { + /* Determine the OpCode based on message type attribute */ + struct wps_parse_attr attr; + + if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) { + if (*attr.msg_type == WPS_WSC_ACK) { + op_code = WSC_ACK; + } else if (*attr.msg_type == WPS_WSC_NACK) { + op_code = WSC_NACK; + } + } + } + + switch (op_code) { + case WSC_Start: + return wps_process_wsc_start(wps, msg); + + case WSC_MSG: + case WSC_UPnP: + return wps_process_wsc_msg(wps, msg); + + case WSC_ACK: + if (wps_validate_wsc_ack(msg) < 0) { + return WPS_FAILURE; + } + + return wps_process_wsc_ack(wps, msg); + + case WSC_NACK: + if (wps_validate_wsc_nack(msg) < 0) { + return WPS_FAILURE; + } + + return wps_process_wsc_nack(wps, msg); + + default: + wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code); + return WPS_FAILURE; + } +} diff --git a/components/wpa_supplicant/src/wps/wps_registrar.c b/components/wpa_supplicant/src/wps/wps_registrar.c new file mode 100644 index 00000000..ccdd9cbd --- /dev/null +++ b/components/wpa_supplicant/src/wps/wps_registrar.c @@ -0,0 +1,3960 @@ +/* + * Wi-Fi Protected Setup - Registrar + * Copyright (c) 2008-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "rom/ets_sys.h" + +#include "wpa/includes.h" +#include "wpa/common.h" +#include "wps/utils/uuid.h" +#include "wpa/list.h" +#include "wpa/ieee802_11_defs.h" +#include "wps/wps_i.h" +#include "wps/wps_dev_attr.h" + +#include "crypto/base64.h" +#include "crypto/crypto.h" +#include "crypto/sha256.h" +#include "crypto/random.h" + +#ifndef CONFIG_WPS_STRICT +#define WPS_WORKAROUNDS +#endif /* CONFIG_WPS_STRICT */ + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +#ifdef CONFIG_WPS_NFC + +struct wps_nfc_pw_token { + struct dl_list list; + u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN]; + u16 pw_id; + u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN]; + size_t dev_pw_len; +}; + + +static void ICACHE_FLASH_ATTR wps_remove_nfc_pw_token(struct wps_nfc_pw_token* token) +{ + dl_list_del(&token->list); + os_free(token); +} + + +static void ICACHE_FLASH_ATTR wps_free_nfc_pw_tokens(struct dl_list* tokens, u16 pw_id) +{ + struct wps_nfc_pw_token* token, *prev; + dl_list_for_each_safe(token, prev, tokens, struct wps_nfc_pw_token, + list) { + if (pw_id == 0 || pw_id == token->pw_id) { + wps_remove_nfc_pw_token(token); + } + } +} + + +static struct wps_nfc_pw_token* wps_get_nfc_pw_token(struct dl_list* tokens, + u16 pw_id) +{ + struct wps_nfc_pw_token* token; + dl_list_for_each(token, tokens, struct wps_nfc_pw_token, list) { + if (pw_id == token->pw_id) { + return token; + } + } + return NULL; +} + +#else /* CONFIG_WPS_NFC */ + +#define wps_free_nfc_pw_tokens(t, p) do { } while (0) + +#endif /* CONFIG_WPS_NFC */ + +#ifdef CONFIG_WPS_PIN + +struct wps_uuid_pin { + struct dl_list list; + u8 uuid[WPS_UUID_LEN]; + int wildcard_uuid; + u8* pin; + size_t pin_len; +#define PIN_LOCKED BIT(0) +#define PIN_EXPIRES BIT(1) + int flags; + struct os_time expiration; + u8 enrollee_addr[ETH_ALEN]; +}; + + +static void ICACHE_FLASH_ATTR wps_free_pin(struct wps_uuid_pin* pin) +{ + os_free(pin->pin); + os_free(pin); +} + + +static void ICACHE_FLASH_ATTR wps_remove_pin(struct wps_uuid_pin* pin) +{ + dl_list_del(&pin->list); + wps_free_pin(pin); +} + + +static void ICACHE_FLASH_ATTR wps_free_pins(struct dl_list* pins) +{ + struct wps_uuid_pin* pin, *prev; + dl_list_for_each_safe(pin, prev, pins, struct wps_uuid_pin, list) + wps_remove_pin(pin); +} + +#endif + +struct wps_pbc_session { + struct wps_pbc_session* next; + u8 addr[ETH_ALEN]; + u8 uuid_e[WPS_UUID_LEN]; + struct os_time timestamp; +}; + + +static void ICACHE_FLASH_ATTR wps_free_pbc_sessions(struct wps_pbc_session* pbc) +{ + struct wps_pbc_session* prev; + + while (pbc) { + prev = pbc; + pbc = pbc->next; + os_free(prev); + } +} + + +struct wps_registrar_device { + struct wps_registrar_device* next; + struct wps_device_data dev; + u8 uuid[WPS_UUID_LEN]; +}; + + +struct wps_registrar { + struct wps_context* wps; + + int pbc; + int selected_registrar; + + int (*new_psk_cb)(void* ctx, const u8* mac_addr, const u8* psk, + size_t psk_len); + int (*set_ie_cb)(void* ctx, struct wpabuf* beacon_ie, + struct wpabuf* probe_resp_ie); + void (*pin_needed_cb)(void* ctx, const u8* uuid_e, + const struct wps_device_data* dev); + void (*reg_success_cb)(void* ctx, const u8* mac_addr, + const u8* uuid_e, const u8* dev_pw, + size_t dev_pw_len); + void (*set_sel_reg_cb)(void* ctx, int sel_reg, u16 dev_passwd_id, + u16 sel_reg_config_methods); + void (*enrollee_seen_cb)(void* ctx, const u8* addr, const u8* uuid_e, + const u8* pri_dev_type, u16 config_methods, + u16 dev_password_id, u8 request_type, + const char* dev_name); + void* cb_ctx; + + struct dl_list pins; + struct dl_list nfc_pw_tokens; + struct wps_pbc_session* pbc_sessions; + + int skip_cred_build; + struct wpabuf* extra_cred; + int disable_auto_conf; + int sel_reg_union; + int sel_reg_dev_password_id_override; + int sel_reg_config_methods_override; + int static_wep_only; + int dualband; + + struct wps_registrar_device* devices; + + int force_pbc_overlap; + + u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN]; + u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN]; + + u8 p2p_dev_addr[ETH_ALEN]; + + u8 pbc_ignore_uuid[WPS_UUID_LEN]; + struct os_time pbc_ignore_start; +}; + + +static int wps_set_ie(struct wps_registrar* reg); +//static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx); +//static void wps_registrar_set_selected_timeout(void *eloop_ctx, +// void *timeout_ctx); +static void wps_registrar_pbc_timeout(void* eloop_ctx); +//static void wps_registrar_set_selected_timeout(void *eloop_ctx); + +#ifdef CONFIG_WPS_PIN + +static void wps_registrar_remove_pin(struct wps_registrar* reg, + struct wps_uuid_pin* pin); +#endif + +static void ICACHE_FLASH_ATTR wps_registrar_add_authorized_mac(struct wps_registrar* reg, + const u8* addr) +{ + int i; + wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC " MACSTR, + MAC2STR(addr)); + + for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) + if (os_memcmp(reg->authorized_macs[i], addr, ETH_ALEN) == 0) { + wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was " + "already in the list"); + return; /* already in list */ + } + + for (i = WPS_MAX_AUTHORIZED_MACS - 1; i > 0; i--) + os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i - 1], + ETH_ALEN); + + os_memcpy(reg->authorized_macs[0], addr, ETH_ALEN); + wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs", + (u8*) reg->authorized_macs, sizeof(reg->authorized_macs)); +} + + +static void ICACHE_FLASH_ATTR wps_registrar_remove_authorized_mac(struct wps_registrar* reg, + const u8* addr) +{ + int i; + wpa_printf(MSG_DEBUG, "WPS: Remove authorized MAC " MACSTR, + MAC2STR(addr)); + + for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) { + if (os_memcmp(reg->authorized_macs, addr, ETH_ALEN) == 0) { + break; + } + } + + if (i == WPS_MAX_AUTHORIZED_MACS) { + wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was not in the " + "list"); + return; /* not in the list */ + } + + for (; i + 1 < WPS_MAX_AUTHORIZED_MACS; i++) + os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i + 1], + ETH_ALEN); + + os_memset(reg->authorized_macs[WPS_MAX_AUTHORIZED_MACS - 1], 0, + ETH_ALEN); + wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs", + (u8*) reg->authorized_macs, sizeof(reg->authorized_macs)); +} + + +static void ICACHE_FLASH_ATTR wps_free_devices(struct wps_registrar_device* dev) +{ + struct wps_registrar_device* prev; + + while (dev) { + prev = dev; + dev = dev->next; + wps_device_data_free(&prev->dev); + os_free(prev); + } +} + + +static struct wps_registrar_device* ICACHE_FLASH_ATTR wps_device_get(struct wps_registrar* reg, + const u8* addr) +{ + struct wps_registrar_device* dev; + + for (dev = reg->devices; dev; dev = dev->next) { + if (os_memcmp(dev->dev.mac_addr, addr, ETH_ALEN) == 0) { + return dev; + } + } + + return NULL; +} + + +static void ICACHE_FLASH_ATTR wps_device_clone_data(struct wps_device_data* dst, + struct wps_device_data* src) +{ + os_memcpy(dst->mac_addr, src->mac_addr, ETH_ALEN); + os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN); + +#define WPS_STRDUP(n) \ + os_free(dst->n); \ + dst->n = src->n ? os_strdup(src->n) : NULL + + WPS_STRDUP(device_name); + WPS_STRDUP(manufacturer); + WPS_STRDUP(model_name); + WPS_STRDUP(model_number); + WPS_STRDUP(serial_number); +#undef WPS_STRDUP +} + + +int ICACHE_FLASH_ATTR wps_device_store(struct wps_registrar* reg, + struct wps_device_data* dev, const u8* uuid) +{ + struct wps_registrar_device* d; + + d = wps_device_get(reg, dev->mac_addr); + + if (d == NULL) { + d = (struct wps_registrar_device*)os_zalloc(sizeof(*d)); + + if (d == NULL) { + return -1; + } + + d->next = reg->devices; + reg->devices = d; + } + + wps_device_clone_data(&d->dev, dev); + os_memcpy(d->uuid, uuid, WPS_UUID_LEN); + + return 0; +} + + +static void ICACHE_FLASH_ATTR wps_registrar_add_pbc_session(struct wps_registrar* reg, + const u8* addr, const u8* uuid_e) +{ + struct wps_pbc_session* pbc, *prev = NULL; + struct os_time now; + + os_get_time(&now); + + pbc = reg->pbc_sessions; + + while (pbc) { + if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 && + os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) { + if (prev) { + prev->next = pbc->next; + } else { + reg->pbc_sessions = pbc->next; + } + + break; + } + + prev = pbc; + pbc = pbc->next; + } + + if (!pbc) { + pbc = (struct wps_pbc_session*)os_zalloc(sizeof(*pbc)); + + if (pbc == NULL) { + return; + } + + os_memcpy(pbc->addr, addr, ETH_ALEN); + + if (uuid_e) { + os_memcpy(pbc->uuid_e, uuid_e, WPS_UUID_LEN); + } + } + + pbc->next = reg->pbc_sessions; + reg->pbc_sessions = pbc; + pbc->timestamp = now; + + /* remove entries that have timed out */ + prev = pbc; + pbc = pbc->next; + + while (pbc) { + if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) { + prev->next = NULL; + wps_free_pbc_sessions(pbc); + break; + } + + prev = pbc; + pbc = pbc->next; + } +} + + +static void ICACHE_FLASH_ATTR wps_registrar_remove_pbc_session(struct wps_registrar* reg, + const u8* uuid_e, + const u8* p2p_dev_addr) +{ + struct wps_pbc_session* pbc, *prev = NULL, *tmp; + + pbc = reg->pbc_sessions; + + while (pbc) { + if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 || + (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) && + os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) == + 0)) { + if (prev) { + prev->next = pbc->next; + } else { + reg->pbc_sessions = pbc->next; + } + + tmp = pbc; + pbc = pbc->next; + wpa_printf(MSG_DEBUG, "WPS: Removing PBC session for " + "addr=" MACSTR, MAC2STR(tmp->addr)); + wpa_hexdump(MSG_DEBUG, "WPS: Removed UUID-E", + tmp->uuid_e, WPS_UUID_LEN); + os_free(tmp); + continue; + } + + prev = pbc; + pbc = pbc->next; + } +} + + +int ICACHE_FLASH_ATTR wps_registrar_pbc_overlap(struct wps_registrar* reg, + const u8* addr, const u8* uuid_e) +{ + int count = 0; + struct wps_pbc_session* pbc; + struct wps_pbc_session* first = NULL; + struct os_time now; + + os_get_time(&now); + + wpa_printf(MSG_DEBUG, "WPS: Checking active PBC sessions for overlap"); + + if (uuid_e) { + wpa_printf(MSG_DEBUG, "WPS: Add one for the requested UUID"); + wpa_hexdump(MSG_DEBUG, "WPS: Requested UUID", + uuid_e, WPS_UUID_LEN); + count++; + } + + for (pbc = reg->pbc_sessions; pbc; pbc = pbc->next) { + wpa_printf(MSG_DEBUG, "WPS: Consider PBC session with " MACSTR, + MAC2STR(pbc->addr)); + wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", + pbc->uuid_e, WPS_UUID_LEN); + + if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) { + wpa_printf(MSG_DEBUG, "WPS: PBC walk time has " + "expired"); + break; + } + + if (first && + os_memcmp(pbc->uuid_e, first->uuid_e, WPS_UUID_LEN) == 0) { + wpa_printf(MSG_DEBUG, "WPS: Same Enrollee"); + continue; /* same Enrollee */ + } + + if (uuid_e == NULL || + os_memcmp(uuid_e, pbc->uuid_e, WPS_UUID_LEN)) { + wpa_printf(MSG_DEBUG, "WPS: New Enrollee"); + count++; + } + + if (first == NULL) { + first = pbc; + } + } + + wpa_printf(MSG_DEBUG, "WPS: %u active PBC session(s) found", count); + + return count > 1 ? 1 : 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_wps_state(struct wps_context* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)", + wps->wps_state); + wpabuf_put_be16(msg, ATTR_WPS_STATE); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, wps->wps_state); + return 0; +} + + +#ifdef CONFIG_WPS_UPNP +static void ICACHE_FLASH_ATTR wps_registrar_free_pending_m2(struct wps_context* wps) +{ + struct upnp_pending_message* p, *p2, *prev = NULL; + p = wps->upnp_msgs; + + while (p) { + if (p->type == WPS_M2 || p->type == WPS_M2D) { + if (prev == NULL) { + wps->upnp_msgs = p->next; + } else { + prev->next = p->next; + } + + wpa_printf(MSG_DEBUG, "WPS UPnP: Drop pending M2/M2D"); + p2 = p; + p = p->next; + wpabuf_free(p2->msg); + os_free(p2); + continue; + } + + prev = p; + p = p->next; + } +} +#endif /* CONFIG_WPS_UPNP */ + + +static int ICACHE_FLASH_ATTR wps_build_ap_setup_locked(struct wps_context* wps, + struct wpabuf* msg) +{ + if (wps->ap_setup_locked && wps->ap_setup_locked != 2) { + wpa_printf(MSG_DEBUG, "WPS: * AP Setup Locked"); + wpabuf_put_be16(msg, ATTR_AP_SETUP_LOCKED); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, 1); + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_selected_registrar(struct wps_registrar* reg, + struct wpabuf* msg) +{ + if (!reg->sel_reg_union) { + return 0; + } + + wpa_printf(MSG_DEBUG, "WPS: * Selected Registrar"); + wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, 1); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_sel_reg_dev_password_id(struct wps_registrar* reg, + struct wpabuf* msg) +{ + u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT; + + if (!reg->sel_reg_union) { + return 0; + } + + if (reg->sel_reg_dev_password_id_override >= 0) { + id = reg->sel_reg_dev_password_id_override; + } + + wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id); + wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, id); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_sel_pbc_reg_uuid_e(struct wps_registrar* reg, + struct wpabuf* msg) +{ + u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT; + + if (!reg->sel_reg_union) { + return 0; + } + + if (reg->sel_reg_dev_password_id_override >= 0) { + id = reg->sel_reg_dev_password_id_override; + } + + if (id != DEV_PW_PUSHBUTTON || !reg->dualband) { + return 0; + } + + return wps_build_uuid_e(msg, reg->wps->uuid); +} + + +static void ICACHE_FLASH_ATTR wps_set_pushbutton(u16* methods, u16 conf_methods) +{ + *methods |= WPS_CONFIG_PUSHBUTTON; +#ifdef CONFIG_WPS2 + + if ((conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON) == + WPS_CONFIG_VIRT_PUSHBUTTON) { + *methods |= WPS_CONFIG_VIRT_PUSHBUTTON; + } + + if ((conf_methods & WPS_CONFIG_PHY_PUSHBUTTON) == + WPS_CONFIG_PHY_PUSHBUTTON) { + *methods |= WPS_CONFIG_PHY_PUSHBUTTON; + } + + if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) != + WPS_CONFIG_VIRT_PUSHBUTTON && + (*methods & WPS_CONFIG_PHY_PUSHBUTTON) != + WPS_CONFIG_PHY_PUSHBUTTON) { + /* + * Required to include virtual/physical flag, but we were not + * configured with push button type, so have to default to one + * of them. + */ + *methods |= WPS_CONFIG_PHY_PUSHBUTTON; + } + +#endif /* CONFIG_WPS2 */ +} + + +static int ICACHE_FLASH_ATTR wps_build_sel_reg_config_methods(struct wps_registrar* reg, + struct wpabuf* msg) +{ + u16 methods; + + if (!reg->sel_reg_union) { + return 0; + } + + methods = reg->wps->config_methods; + methods &= ~WPS_CONFIG_PUSHBUTTON; +#ifdef CONFIG_WPS2 + methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | + WPS_CONFIG_PHY_PUSHBUTTON); +#endif /* CONFIG_WPS2 */ + + if (reg->pbc) { + wps_set_pushbutton(&methods, reg->wps->config_methods); + } + + if (reg->sel_reg_config_methods_override >= 0) { + methods = reg->sel_reg_config_methods_override; + } + + wpa_printf(MSG_DEBUG, "WPS: * Selected Registrar Config Methods (%x)", + methods); + wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, methods); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_probe_config_methods(struct wps_registrar* reg, + struct wpabuf* msg) +{ + u16 methods; + /* + * These are the methods that the AP supports as an Enrollee for adding + * external Registrars. + */ + methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; +#ifdef CONFIG_WPS2 + methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | + WPS_CONFIG_PHY_PUSHBUTTON); +#endif /* CONFIG_WPS2 */ + wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods); + wpabuf_put_be16(msg, ATTR_CONFIG_METHODS); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, methods); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_config_methods_r(struct wps_registrar* reg, + struct wpabuf* msg) +{ + return wps_build_config_methods(msg, reg->wps->config_methods); +} + + +const u8* ICACHE_FLASH_ATTR wps_authorized_macs(struct wps_registrar* reg, size_t* count) +{ + *count = 0; + +#ifdef CONFIG_WPS2 + + while (*count < WPS_MAX_AUTHORIZED_MACS) { + if (is_zero_ether_addr(reg->authorized_macs_union[*count])) { + break; + } + + (*count)++; + } + +#endif /* CONFIG_WPS2 */ + + return (const u8*) reg->authorized_macs_union; +} + + +/** + * wps_registrar_init - Initialize WPS Registrar data + * @wps: Pointer to longterm WPS context + * @cfg: Registrar configuration + * Returns: Pointer to allocated Registrar data or %NULL on failure + * + * This function is used to initialize WPS Registrar functionality. It can be + * used for a single Registrar run (e.g., when run in a supplicant) or multiple + * runs (e.g., when run as an internal Registrar in an AP). Caller is + * responsible for freeing the returned data with wps_registrar_deinit() when + * Registrar functionality is not needed anymore. + */ +struct wps_registrar* ICACHE_FLASH_ATTR +wps_registrar_init(struct wps_context* wps, + const struct wps_registrar_config* cfg) +{ + struct wps_registrar* reg = (struct wps_registrar*)os_zalloc(sizeof(*reg)); + + if (reg == NULL) { + return NULL; + } + +#ifdef CONFIG_WPS_PIN + dl_list_init(®->pins); +#endif +#ifdef CONFIG_WPS_NFC + dl_list_init(®->nfc_pw_tokens); +#endif + reg->wps = wps; + reg->new_psk_cb = cfg->new_psk_cb; + reg->set_ie_cb = cfg->set_ie_cb; +#ifdef CONFIG_WPS_PIN + reg->pin_needed_cb = cfg->pin_needed_cb; +#endif + reg->reg_success_cb = cfg->reg_success_cb; + reg->set_sel_reg_cb = cfg->set_sel_reg_cb; + reg->enrollee_seen_cb = cfg->enrollee_seen_cb; + reg->cb_ctx = cfg->cb_ctx; + reg->skip_cred_build = cfg->skip_cred_build; + + if (cfg->extra_cred) { + reg->extra_cred = wpabuf_alloc_copy(cfg->extra_cred, + cfg->extra_cred_len); + + if (reg->extra_cred == NULL) { + os_free(reg); + return NULL; + } + } + + reg->disable_auto_conf = cfg->disable_auto_conf; + reg->sel_reg_dev_password_id_override = -1; + reg->sel_reg_config_methods_override = -1; + reg->static_wep_only = cfg->static_wep_only; + reg->dualband = cfg->dualband; + + if (wps_set_ie(reg)) { + wps_registrar_deinit(reg); + return NULL; + } + + return reg; +} + + +/** + * wps_registrar_deinit - Deinitialize WPS Registrar data + * @reg: Registrar data from wps_registrar_init() + */ +void ICACHE_FLASH_ATTR wps_registrar_deinit(struct wps_registrar* reg) +{ + if (reg == NULL) { + return; + } + + //eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); + //eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); + + // TODO: snake to check, no sys_untimeout now, by wujg +// sys_untimeout(wps_registrar_pbc_timeout, reg); +// sys_untimeout(wps_registrar_set_selected_timeout, reg); + +#ifdef CONFIG_WPS_PIN + wps_free_pins(®->pins); +#endif +#ifdef CONFIG_WPS_NFC + wps_free_nfc_pw_tokens(®->nfc_pw_tokens, 0); +#endif + wps_free_pbc_sessions(reg->pbc_sessions); + wpabuf_free(reg->extra_cred); + wps_free_devices(reg->devices); + os_free(reg); +} + +#ifdef CONFIG_WPS_PIN + +static void ICACHE_FLASH_ATTR wps_registrar_invalidate_unused(struct wps_registrar* reg) +{ + struct wps_uuid_pin* pin; + + dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) { + if (pin->wildcard_uuid == 1 && !(pin->flags & PIN_LOCKED)) { + wpa_printf(MSG_DEBUG, "WPS: Invalidate previously " + "configured wildcard PIN"); + wps_registrar_remove_pin(reg, pin); + break; + } + } +} + + +/** + * wps_registrar_add_pin - Configure a new PIN for Registrar + * @reg: Registrar data from wps_registrar_init() + * @addr: Enrollee MAC address or %NULL if not known + * @uuid: UUID-E or %NULL for wildcard (any UUID) + * @pin: PIN (Device Password) + * @pin_len: Length of pin in octets + * @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout + * Returns: 0 on success, -1 on failure + */ +int ICACHE_FLASH_ATTR wps_registrar_add_pin(struct wps_registrar* reg, const u8* addr, + const u8* uuid, const u8* pin, size_t pin_len, + int timeout) +{ + struct wps_uuid_pin* p; + + p = (struct wps_uuid_pin*)os_zalloc(sizeof(*p)); + + if (p == NULL) { + return -1; + } + + if (addr) { + os_memcpy(p->enrollee_addr, addr, ETH_ALEN); + } + + if (uuid == NULL) { + p->wildcard_uuid = 1; + } else { + os_memcpy(p->uuid, uuid, WPS_UUID_LEN); + } + + p->pin = (u8*)os_malloc(pin_len); + + if (p->pin == NULL) { + os_free(p); + return -1; + } + + os_memcpy(p->pin, pin, pin_len); + p->pin_len = pin_len; + + if (timeout) { + p->flags |= PIN_EXPIRES; + os_get_time(&p->expiration); + p->expiration.sec += timeout; + } + + if (p->wildcard_uuid) { + wps_registrar_invalidate_unused(reg); + } + + dl_list_add(®->pins, &p->list); + + wpa_printf(MSG_DEBUG, "WPS: A new PIN configured (timeout=%d)", + timeout); + wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN); + wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len); + reg->selected_registrar = 1; + reg->pbc = 0; + + if (addr) { + wps_registrar_add_authorized_mac(reg, addr); + } else + wps_registrar_add_authorized_mac( + reg, (u8*) "\xff\xff\xff\xff\xff\xff"); + + wps_registrar_selected_registrar_changed(reg); + //eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); + //eloop_register_timeout(WPS_PBC_WALK_TIME, 0, + //wps_registrar_set_selected_timeout, + //reg, NULL); + + return 0; +} + + +static void ICACHE_FLASH_ATTR wps_registrar_remove_pin(struct wps_registrar* reg, + struct wps_uuid_pin* pin) +{ + u8* addr; + u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + if (is_zero_ether_addr(pin->enrollee_addr)) { + addr = bcast; + } else { + addr = pin->enrollee_addr; + } + + wps_registrar_remove_authorized_mac(reg, addr); + wps_remove_pin(pin); + wps_registrar_selected_registrar_changed(reg); +} + + +static void ICACHE_FLASH_ATTR wps_registrar_expire_pins(struct wps_registrar* reg) +{ + struct wps_uuid_pin* pin, *prev; + struct os_time now; + + os_get_time(&now); + dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list) { + if ((pin->flags & PIN_EXPIRES) && + os_time_before(&pin->expiration, &now)) { + wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID", + pin->uuid, WPS_UUID_LEN); + wps_registrar_remove_pin(reg, pin); + } + } +} + + +/** + * wps_registrar_invalidate_wildcard_pin - Invalidate a wildcard PIN + * @reg: Registrar data from wps_registrar_init() + * @dev_pw: PIN to search for or %NULL to match any + * @dev_pw_len: Length of dev_pw in octets + * Returns: 0 on success, -1 if not wildcard PIN is enabled + */ +static int ICACHE_FLASH_ATTR wps_registrar_invalidate_wildcard_pin(struct wps_registrar* reg, + const u8* dev_pw, + size_t dev_pw_len) +{ + struct wps_uuid_pin* pin, *prev; + + dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list) { + if (dev_pw && pin->pin && + (dev_pw_len != pin->pin_len || + os_memcmp(dev_pw, pin->pin, dev_pw_len) != 0)) { + continue; /* different PIN */ + } + + if (pin->wildcard_uuid) { + wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID", + pin->uuid, WPS_UUID_LEN); + wps_registrar_remove_pin(reg, pin); + return 0; + } + } + + return -1; +} + + +/** + * wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E + * @reg: Registrar data from wps_registrar_init() + * @uuid: UUID-E + * Returns: 0 on success, -1 on failure (e.g., PIN not found) + */ +int ICACHE_FLASH_ATTR wps_registrar_invalidate_pin(struct wps_registrar* reg, const u8* uuid) +{ + struct wps_uuid_pin* pin, *prev; + + dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list) { + if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) { + wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID", + pin->uuid, WPS_UUID_LEN); + wps_registrar_remove_pin(reg, pin); + return 0; + } + } + + return -1; +} + + +static const u8* ICACHE_FLASH_ATTR wps_registrar_get_pin(struct wps_registrar* reg, + const u8* uuid, size_t* pin_len) +{ + struct wps_uuid_pin* pin, *found = NULL; + + wps_registrar_expire_pins(reg); + + dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) { + if (!pin->wildcard_uuid && + os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) { + found = pin; + break; + } + } + + if (!found) { + /* Check for wildcard UUIDs since none of the UUID-specific + * PINs matched */ + dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) { + if (pin->wildcard_uuid == 1 || + pin->wildcard_uuid == 2) { + wpa_printf(MSG_DEBUG, "WPS: Found a wildcard " + "PIN. Assigned it for this UUID-E"); + pin->wildcard_uuid++; + os_memcpy(pin->uuid, uuid, WPS_UUID_LEN); + found = pin; + break; + } + } + } + + if (!found) { + return NULL; + } + + /* + * Lock the PIN to avoid attacks based on concurrent re-use of the PIN + * that could otherwise avoid PIN invalidations. + */ + if (found->flags & PIN_LOCKED) { + wpa_printf(MSG_DEBUG, "WPS: Selected PIN locked - do not " + "allow concurrent re-use"); + return NULL; + } + + *pin_len = found->pin_len; + found->flags |= PIN_LOCKED; + return found->pin; +} + + +/** + * wps_registrar_unlock_pin - Unlock a PIN for a specific UUID-E + * @reg: Registrar data from wps_registrar_init() + * @uuid: UUID-E + * Returns: 0 on success, -1 on failure + * + * PINs are locked to enforce only one concurrent use. This function unlocks a + * PIN to allow it to be used again. If the specified PIN was configured using + * a wildcard UUID, it will be removed instead of allowing multiple uses. + */ +int ICACHE_FLASH_ATTR wps_registrar_unlock_pin(struct wps_registrar* reg, const u8* uuid) +{ + struct wps_uuid_pin* pin; + + dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) { + if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) { + if (pin->wildcard_uuid == 3) { + wpa_printf(MSG_DEBUG, "WPS: Invalidating used " + "wildcard PIN"); + return wps_registrar_invalidate_pin(reg, uuid); + } + + pin->flags &= ~PIN_LOCKED; + return 0; + } + } + + return -1; +} +#endif + +static void ICACHE_FLASH_ATTR wps_registrar_stop_pbc(struct wps_registrar* reg) +{ + reg->selected_registrar = 0; + reg->pbc = 0; + os_memset(reg->p2p_dev_addr, 0, ETH_ALEN); + wps_registrar_remove_authorized_mac(reg, + (u8*) "\xff\xff\xff\xff\xff\xff"); + wps_registrar_selected_registrar_changed(reg); +} + + +//static void ICACHE_FLASH_ATTR wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx) +static void ICACHE_FLASH_ATTR wps_registrar_pbc_timeout(void* eloop_ctx) +{ + struct wps_registrar* reg = eloop_ctx; + + wpa_printf(MSG_DEBUG, "WPS: PBC timed out - disable PBC mode"); + wps_pbc_timeout_event(reg->wps); + wps_registrar_stop_pbc(reg); +} + + +/** + * wps_registrar_button_pushed - Notify Registrar that AP button was pushed + * @reg: Registrar data from wps_registrar_init() + * @p2p_dev_addr: Limit allowed PBC devices to the specified P2P device, %NULL + * indicates no such filtering + * Returns: 0 on success, -1 on failure, -2 on session overlap + * + * This function is called on an AP when a push button is pushed to activate + * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout + * or when a PBC registration is completed. If more than one Enrollee in active + * PBC mode has been detected during the monitor time (previous 2 minutes), the + * PBC mode is not activated and -2 is returned to indicate session overlap. + * This is skipped if a specific Enrollee is selected. + */ +int ICACHE_FLASH_ATTR wps_registrar_button_pushed(struct wps_registrar* reg, + const u8* p2p_dev_addr) +{ + if (p2p_dev_addr == NULL && + wps_registrar_pbc_overlap(reg, NULL, NULL)) { + wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC " + "mode"); + wps_pbc_overlap_event(reg->wps); + return -2; + } + + wpa_printf(MSG_DEBUG, "WPS: Button pushed - PBC mode started"); + reg->force_pbc_overlap = 0; + reg->selected_registrar = 1; + reg->pbc = 1; + + if (p2p_dev_addr) { + os_memcpy(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN); + } else { + os_memset(reg->p2p_dev_addr, 0, ETH_ALEN); + } + + wps_registrar_add_authorized_mac(reg, + (u8*) "\xff\xff\xff\xff\xff\xff"); + wps_registrar_selected_registrar_changed(reg); + + //eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); + //eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); + + // TODO: snake to check, no sys_untimeout now, by wujg +// sys_untimeout(wps_registrar_set_selected_timeout, reg); +// sys_untimeout(wps_registrar_pbc_timeout, reg); + + //eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout, + // reg, NULL); +// sys_timeout(WPS_PBC_WALK_TIME*1000, wps_registrar_pbc_timeout, reg); + + return 0; +} + + +static void ICACHE_FLASH_ATTR wps_registrar_pbc_completed(struct wps_registrar* reg) +{ + wpa_printf(MSG_DEBUG, "WPS: PBC completed - stopping PBC mode"); + //eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); +// sys_untimeout(wps_registrar_pbc_timeout, reg); + + wps_registrar_stop_pbc(reg); +} + +#ifdef CONFIG_WPS_PIN + +static void ICACHE_FLASH_ATTR wps_registrar_pin_completed(struct wps_registrar* reg) +{ + wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar"); + //eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); + reg->selected_registrar = 0; + wps_registrar_selected_registrar_changed(reg); +} +#endif + +void ICACHE_FLASH_ATTR wps_registrar_complete(struct wps_registrar* registrar, const u8* uuid_e, + const u8* dev_pw, size_t dev_pw_len) +{ + if (registrar->pbc) { + wps_registrar_remove_pbc_session(registrar, + uuid_e, NULL); + wps_registrar_pbc_completed(registrar); + os_get_time(®istrar->pbc_ignore_start); + os_memcpy(registrar->pbc_ignore_uuid, uuid_e, WPS_UUID_LEN); + } else { +#ifdef CONFIG_WPS_PIN + wps_registrar_pin_completed(registrar); +#endif + } + +#ifdef CONFIG_WPS_PIN + + if (dev_pw && + wps_registrar_invalidate_wildcard_pin(registrar, dev_pw, + dev_pw_len) == 0) { + wpa_hexdump_key(MSG_DEBUG, "WPS: Invalidated wildcard PIN", + dev_pw, dev_pw_len); + } + +#endif +} + + +int ICACHE_FLASH_ATTR wps_registrar_wps_cancel(struct wps_registrar* reg) +{ + if (reg->pbc) { + wpa_printf(MSG_DEBUG, "WPS: PBC is set - cancelling it"); + //wps_registrar_pbc_timeout(reg, NULL); + //eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); + wps_registrar_pbc_timeout(reg); + + // TODO: snake to check, no sys_untimeout now, by wujg +// sys_untimeout(wps_registrar_pbc_timeout, reg); + + return 1; + } else if (reg->selected_registrar) { +#ifdef CONFIG_WPS_PIN + + /* PIN Method */ + wpa_printf(MSG_DEBUG, "WPS: PIN is set - cancelling it"); + wps_registrar_pin_completed(reg); + wps_registrar_invalidate_wildcard_pin(reg, NULL, 0); + return 1; +#endif + } + + return 0; +} + + +/** + * wps_registrar_probe_req_rx - Notify Registrar of Probe Request + * @reg: Registrar data from wps_registrar_init() + * @addr: MAC address of the Probe Request sender + * @wps_data: WPS IE contents + * + * This function is called on an AP when a Probe Request with WPS IE is + * received. This is used to track PBC mode use and to detect possible overlap + * situation with other WPS APs. + */ +void ICACHE_FLASH_ATTR wps_registrar_probe_req_rx(struct wps_registrar* reg, const u8* addr, + const struct wpabuf* wps_data, + int p2p_wildcard) +{ + struct wps_parse_attr attr; + int skip_add = 0; + + wpa_hexdump_buf(MSG_MSGDUMP, + "WPS: Probe Request with WPS data received", + wps_data); + + if (wps_parse_msg(wps_data, &attr) < 0) { + return; + } + + if (attr.config_methods == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Config Methods attribute in " + "Probe Request"); + return; + } + + if (attr.dev_password_id == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Device Password Id attribute " + "in Probe Request"); + return; + } + + if (reg->enrollee_seen_cb && attr.uuid_e && + attr.primary_dev_type && attr.request_type && !p2p_wildcard) { + char* dev_name = NULL; + + if (attr.dev_name) { + dev_name = (char*)os_zalloc(attr.dev_name_len + 1); + + if (dev_name) { + os_memcpy(dev_name, attr.dev_name, + attr.dev_name_len); + } + } + + reg->enrollee_seen_cb(reg->cb_ctx, addr, attr.uuid_e, + attr.primary_dev_type, + WPA_GET_BE16(attr.config_methods), + WPA_GET_BE16(attr.dev_password_id), + *attr.request_type, dev_name); + os_free(dev_name); + } + + if (WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) { + return; /* Not PBC */ + } + + wpa_printf(MSG_DEBUG, "WPS: Probe Request for PBC received from " + MACSTR, MAC2STR(addr)); + + if (attr.uuid_e == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Probe Request WPS IE: No " + "UUID-E included"); + return; + } + + wpa_hexdump(MSG_DEBUG, "WPS: UUID-E from Probe Request", attr.uuid_e, + WPS_UUID_LEN); + +#ifdef WPS_WORKAROUNDS + + if (reg->pbc_ignore_start.sec && + os_memcmp(attr.uuid_e, reg->pbc_ignore_uuid, WPS_UUID_LEN) == 0) { + struct os_time now, dur; + os_get_time(&now); + os_time_sub(&now, ®->pbc_ignore_start, &dur); + + if (dur.sec >= 0 && dur.sec < 5) { + wpa_printf(MSG_DEBUG, "WPS: Ignore PBC activation " + "based on Probe Request from the Enrollee " + "that just completed PBC provisioning"); + skip_add = 1; + } else { + reg->pbc_ignore_start.sec = 0; + } + } + +#endif /* WPS_WORKAROUNDS */ + + if (!skip_add) { + wps_registrar_add_pbc_session(reg, addr, attr.uuid_e); + } + + if (wps_registrar_pbc_overlap(reg, addr, attr.uuid_e)) { + wpa_printf(MSG_DEBUG, "WPS: PBC session overlap detected"); + reg->force_pbc_overlap = 1; + wps_pbc_overlap_event(reg->wps); + } +} + + +static int ICACHE_FLASH_ATTR wps_cb_new_psk(struct wps_registrar* reg, const u8* mac_addr, + const u8* psk, size_t psk_len) +{ + if (reg->new_psk_cb == NULL) { + return 0; + } + + return reg->new_psk_cb(reg->cb_ctx, mac_addr, psk, psk_len); +} + +#ifdef CONFIG_WPS_PIN + +static void ICACHE_FLASH_ATTR wps_cb_pin_needed(struct wps_registrar* reg, const u8* uuid_e, + const struct wps_device_data* dev) +{ + if (reg->pin_needed_cb == NULL) { + return; + } + + reg->pin_needed_cb(reg->cb_ctx, uuid_e, dev); +} +#endif + +static void ICACHE_FLASH_ATTR wps_cb_reg_success(struct wps_registrar* reg, const u8* mac_addr, + const u8* uuid_e, const u8* dev_pw, + size_t dev_pw_len) +{ + if (reg->reg_success_cb == NULL) { + return; + } + + reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e, dev_pw, dev_pw_len); +} + + +static int ICACHE_FLASH_ATTR wps_cb_set_ie(struct wps_registrar* reg, struct wpabuf* beacon_ie, + struct wpabuf* probe_resp_ie) +{ + return reg->set_ie_cb(reg->cb_ctx, beacon_ie, probe_resp_ie); +} + + +static void ICACHE_FLASH_ATTR wps_cb_set_sel_reg(struct wps_registrar* reg) +{ + u16 methods = 0; + + if (reg->set_sel_reg_cb == NULL) { + return; + } + + if (reg->selected_registrar) { + methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; +#ifdef CONFIG_WPS2 + methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | + WPS_CONFIG_PHY_PUSHBUTTON); +#endif /* CONFIG_WPS2 */ + + if (reg->pbc) { + wps_set_pushbutton(&methods, reg->wps->config_methods); + } + } + + wpa_printf(MSG_DEBUG, "WPS: wps_cb_set_sel_reg: sel_reg=%d " + "config_methods=0x%x pbc=%d methods=0x%x", + reg->selected_registrar, reg->wps->config_methods, + reg->pbc, methods); + + reg->set_sel_reg_cb(reg->cb_ctx, reg->selected_registrar, + reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT, + methods); +} + + +static int ICACHE_FLASH_ATTR wps_set_ie(struct wps_registrar* reg) +{ + struct wpabuf* beacon; + struct wpabuf* probe; + const u8* auth_macs; + size_t count; + size_t vendor_len = 0; + int i; + + if (reg->set_ie_cb == NULL) { + return 0; + } + + for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { + if (reg->wps->dev.vendor_ext[i]) { + vendor_len += 2 + 2; + vendor_len += wpabuf_len(reg->wps->dev.vendor_ext[i]); + } + } + + beacon = wpabuf_alloc(400 + vendor_len); + + if (beacon == NULL) { + return -1; + } + + probe = wpabuf_alloc(500 + vendor_len); + + if (probe == NULL) { + wpabuf_free(beacon); + return -1; + } + + auth_macs = wps_authorized_macs(reg, &count); + + wpa_printf(MSG_DEBUG, "WPS: Build Beacon IEs"); + + if (wps_build_version(beacon) || + wps_build_wps_state(reg->wps, beacon) || + wps_build_ap_setup_locked(reg->wps, beacon) || + wps_build_selected_registrar(reg, beacon) || + wps_build_sel_reg_dev_password_id(reg, beacon) || + wps_build_sel_reg_config_methods(reg, beacon) || + wps_build_sel_pbc_reg_uuid_e(reg, beacon) || + (reg->dualband && wps_build_rf_bands(®->wps->dev, beacon)) || + wps_build_wfa_ext(beacon, 0, auth_macs, count) || + wps_build_vendor_ext(®->wps->dev, beacon)) { + wpabuf_free(beacon); + wpabuf_free(probe); + return -1; + } + +#ifdef CONFIG_P2P + + if (wps_build_dev_name(®->wps->dev, beacon) || + wps_build_primary_dev_type(®->wps->dev, beacon)) { + wpabuf_free(beacon); + wpabuf_free(probe); + return -1; + } + +#endif /* CONFIG_P2P */ + + wpa_printf(MSG_DEBUG, "WPS: Build Probe Response IEs"); + + if (wps_build_version(probe) || + wps_build_wps_state(reg->wps, probe) || + wps_build_ap_setup_locked(reg->wps, probe) || + wps_build_selected_registrar(reg, probe) || + wps_build_sel_reg_dev_password_id(reg, probe) || + wps_build_sel_reg_config_methods(reg, probe) || + wps_build_resp_type(probe, reg->wps->ap ? WPS_RESP_AP : + WPS_RESP_REGISTRAR) || + wps_build_uuid_e(probe, reg->wps->uuid) || + wps_build_device_attrs(®->wps->dev, probe) || + wps_build_probe_config_methods(reg, probe) || + (reg->dualband && wps_build_rf_bands(®->wps->dev, probe)) || + wps_build_wfa_ext(probe, 0, auth_macs, count) || + wps_build_vendor_ext(®->wps->dev, probe)) { + wpabuf_free(beacon); + wpabuf_free(probe); + return -1; + } + + beacon = wps_ie_encapsulate(beacon); + probe = wps_ie_encapsulate(probe); + + if (!beacon || !probe) { + wpabuf_free(beacon); + wpabuf_free(probe); + return -1; + } + + if (reg->static_wep_only) { + /* + * Windows XP and Vista clients can get confused about + * EAP-Identity/Request when they probe the network with + * EAPOL-Start. In such a case, they may assume the network is + * using IEEE 802.1X and prompt user for a certificate while + * the correct (non-WPS) behavior would be to ask for the + * static WEP key. As a workaround, use Microsoft Provisioning + * IE to advertise that legacy 802.1X is not supported. + */ + const u8 ms_wps[7] = { + WLAN_EID_VENDOR_SPECIFIC, 5, + /* Microsoft Provisioning IE (00:50:f2:5) */ + 0x00, 0x50, 0xf2, 5, + 0x00 /* no legacy 802.1X or MS WPS */ + }; + wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE " + "into Beacon/Probe Response frames"); + wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps)); + wpabuf_put_data(probe, ms_wps, sizeof(ms_wps)); + } + + return wps_cb_set_ie(reg, beacon, probe); +} + + +static int ICACHE_FLASH_ATTR wps_get_dev_password(struct wps_data* wps) +{ + const u8* pin; + size_t pin_len = 0; + + os_free(wps->dev_password); + wps->dev_password = NULL; + + if (wps->pbc) { + wpa_printf(MSG_DEBUG, "WPS: Use default PIN for PBC"); + pin = (const u8*) "00000000"; + pin_len = 8; +#ifdef CONFIG_WPS_NFC + } else if (wps->nfc_pw_token) { + wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from NFC " + "Password Token"); + pin = wps->nfc_pw_token->dev_pw; + pin_len = wps->nfc_pw_token->dev_pw_len; +#endif /* CONFIG_WPS_NFC */ + } else { +#ifdef CONFIG_WPS_PIN + + pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e, + &pin_len); + } + + if (pin == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Device Password available for " + "the Enrollee"); + wps_cb_pin_needed(wps->wps->registrar, wps->uuid_e, + &wps->peer_dev); + return -1; +#endif + } + + wps->dev_password = (u8*)os_malloc(pin_len); + + if (wps->dev_password == NULL) { + return -1; + } + + os_memcpy(wps->dev_password, pin, pin_len); + wps->dev_password_len = pin_len; + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_uuid_r(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * UUID-R"); + wpabuf_put_be16(msg, ATTR_UUID_R); + wpabuf_put_be16(msg, WPS_UUID_LEN); + wpabuf_put_data(msg, wps->uuid_r, WPS_UUID_LEN); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_r_hash(struct wps_data* wps, struct wpabuf* msg) +{ + u8* hash; + const u8* addr[4]; + size_t len[4]; + + if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0) { + return -1; + } + + wpa_hexdump(MSG_DEBUG, "WPS: R-S1", wps->snonce, WPS_SECRET_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: R-S2", + wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN); + + if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) { + wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for " + "R-Hash derivation"); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: * R-Hash1"); + wpabuf_put_be16(msg, ATTR_R_HASH1); + wpabuf_put_be16(msg, SHA256_MAC_LEN); + hash = wpabuf_put(msg, SHA256_MAC_LEN); + /* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */ + addr[0] = wps->snonce; + len[0] = WPS_SECRET_NONCE_LEN; + addr[1] = wps->psk1; + len[1] = WPS_PSK_LEN; + addr[2] = wpabuf_head(wps->dh_pubkey_e); + len[2] = wpabuf_len(wps->dh_pubkey_e); + addr[3] = wpabuf_head(wps->dh_pubkey_r); + len[3] = wpabuf_len(wps->dh_pubkey_r); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", hash, SHA256_MAC_LEN); + + wpa_printf(MSG_DEBUG, "WPS: * R-Hash2"); + wpabuf_put_be16(msg, ATTR_R_HASH2); + wpabuf_put_be16(msg, SHA256_MAC_LEN); + hash = wpabuf_put(msg, SHA256_MAC_LEN); + /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */ + addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; + addr[1] = wps->psk2; + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", hash, SHA256_MAC_LEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_r_snonce1(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * R-SNonce1"); + wpabuf_put_be16(msg, ATTR_R_SNONCE1); + wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); + wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_r_snonce2(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * R-SNonce2"); + wpabuf_put_be16(msg, ATTR_R_SNONCE2); + wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); + wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN, + WPS_SECRET_NONCE_LEN); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_network_idx(struct wpabuf* msg, + const struct wps_credential* cred) +{ + wpa_printf(MSG_DEBUG, "WPS: * Network Index (1)"); + wpabuf_put_be16(msg, ATTR_NETWORK_INDEX); + wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, 1); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_ssid(struct wpabuf* msg, + const struct wps_credential* cred) +{ + wpa_printf(MSG_DEBUG, "WPS: * SSID"); + wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID for Credential", + cred->ssid, cred->ssid_len); + wpabuf_put_be16(msg, ATTR_SSID); + wpabuf_put_be16(msg, cred->ssid_len); + wpabuf_put_data(msg, cred->ssid, cred->ssid_len); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_auth_type(struct wpabuf* msg, + const struct wps_credential* cred) +{ + wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)", + cred->auth_type); + wpabuf_put_be16(msg, ATTR_AUTH_TYPE); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, cred->auth_type); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_encr_type(struct wpabuf* msg, + const struct wps_credential* cred) +{ + wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)", + cred->encr_type); + wpabuf_put_be16(msg, ATTR_ENCR_TYPE); + wpabuf_put_be16(msg, 2); + wpabuf_put_be16(msg, cred->encr_type); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_network_key(struct wpabuf* msg, + const struct wps_credential* cred) +{ + wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%d)", + (int) cred->key_len); + wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", + cred->key, cred->key_len); + wpabuf_put_be16(msg, ATTR_NETWORK_KEY); + wpabuf_put_be16(msg, cred->key_len); + wpabuf_put_data(msg, cred->key, cred->key_len); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_cred_mac_addr(struct wpabuf* msg, + const struct wps_credential* cred) +{ + wpa_printf(MSG_DEBUG, "WPS: * MAC Address (" MACSTR ")", + MAC2STR(cred->mac_addr)); + wpabuf_put_be16(msg, ATTR_MAC_ADDR); + wpabuf_put_be16(msg, ETH_ALEN); + wpabuf_put_data(msg, cred->mac_addr, ETH_ALEN); + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_credential(struct wpabuf* msg, + const struct wps_credential* cred) +{ + if (wps_build_cred_network_idx(msg, cred) || + wps_build_cred_ssid(msg, cred) || + wps_build_cred_auth_type(msg, cred) || + wps_build_cred_encr_type(msg, cred) || + wps_build_cred_network_key(msg, cred) || + wps_build_cred_mac_addr(msg, cred)) { + return -1; + } + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_credential_wrap(struct wpabuf* msg, + const struct wps_credential* cred) +{ + struct wpabuf* wbuf; + wbuf = wpabuf_alloc(200); + + if (wbuf == NULL) { + return -1; + } + + if (wps_build_credential(wbuf, cred)) { + wpabuf_free(wbuf); + return -1; + } + + wpabuf_put_be16(msg, ATTR_CRED); + wpabuf_put_be16(msg, wpabuf_len(wbuf)); + wpabuf_put_buf(msg, wbuf); + wpabuf_free(wbuf); + return 0; +} + + +int ICACHE_FLASH_ATTR wps_build_cred(struct wps_data* wps, struct wpabuf* msg) +{ + struct wpabuf* cred; + + if (wps->wps->registrar->skip_cred_build) { + goto skip_cred_build; + } + + wpa_printf(MSG_DEBUG, "WPS: * Credential"); + + if (wps->use_cred) { + os_memcpy(&wps->cred, wps->use_cred, sizeof(wps->cred)); + goto use_provided; + } + + os_memset(&wps->cred, 0, sizeof(wps->cred)); + + os_memcpy(wps->cred.ssid, wps->wps->ssid, wps->wps->ssid_len); + wps->cred.ssid_len = wps->wps->ssid_len; + + /* Select the best authentication and encryption type */ + if (wps->auth_type & WPS_AUTH_WPA2PSK) { + wps->auth_type = WPS_AUTH_WPA2PSK; + } else if (wps->auth_type & WPS_AUTH_WPAPSK) { + wps->auth_type = WPS_AUTH_WPAPSK; + } else if (wps->auth_type & WPS_AUTH_OPEN) { + wps->auth_type = WPS_AUTH_OPEN; + } else if (wps->auth_type & WPS_AUTH_SHARED) { + wps->auth_type = WPS_AUTH_SHARED; + } else { + wpa_printf(MSG_DEBUG, "WPS: Unsupported auth_type 0x%x", + wps->auth_type); + return -1; + } + + wps->cred.auth_type = wps->auth_type; + + if (wps->auth_type == WPS_AUTH_WPA2PSK || + wps->auth_type == WPS_AUTH_WPAPSK) { + if (wps->encr_type & WPS_ENCR_AES) { + wps->encr_type = WPS_ENCR_AES; + } else if (wps->encr_type & WPS_ENCR_TKIP) { + wps->encr_type = WPS_ENCR_TKIP; + } else { + wpa_printf(MSG_DEBUG, "WPS: No suitable encryption " + "type for WPA/WPA2"); + return -1; + } + } else { + if (wps->encr_type & WPS_ENCR_WEP) { + wps->encr_type = WPS_ENCR_WEP; + } else if (wps->encr_type & WPS_ENCR_NONE) { + wps->encr_type = WPS_ENCR_NONE; + } else { + wpa_printf(MSG_DEBUG, "WPS: No suitable encryption " + "type for non-WPA/WPA2 mode"); + return -1; + } + } + + wps->cred.encr_type = wps->encr_type; + /* + * Set MAC address in the Credential to be the Enrollee's MAC address + */ + os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN); + + if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->wps->ap && + !wps->wps->registrar->disable_auto_conf) { + u8 r[16]; + + /* Generate a random passphrase */ + if (random_get_bytes(r, sizeof(r)) < 0) { + return -1; + } + + os_free(wps->new_psk); + + //wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len); + if (wps->new_psk == NULL) { + return -1; + } + + wps->new_psk_len--; /* remove newline */ + + while (wps->new_psk_len && + wps->new_psk[wps->new_psk_len - 1] == '=') { + wps->new_psk_len--; + } + + wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Generated passphrase", + wps->new_psk, wps->new_psk_len); + os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len); + wps->cred.key_len = wps->new_psk_len; + } else if (wps->use_psk_key && wps->wps->psk_set) { + char hex[65]; + wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key"); + //wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32); + os_memcpy(wps->cred.key, hex, 32 * 2); + wps->cred.key_len = 32 * 2; + } else if (wps->wps->network_key) { + os_memcpy(wps->cred.key, wps->wps->network_key, + wps->wps->network_key_len); + wps->cred.key_len = wps->wps->network_key_len; + } else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) { + char hex[65]; + /* Generate a random per-device PSK */ + os_free(wps->new_psk); + wps->new_psk_len = 32; + wps->new_psk = (u8*)os_malloc(wps->new_psk_len); + + if (wps->new_psk == NULL) { + return -1; + } + + if (random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) { + os_free(wps->new_psk); + wps->new_psk = NULL; + return -1; + } + + wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK", + wps->new_psk, wps->new_psk_len); + //wpa_snprintf_hex(hex, sizeof(hex), wps->new_psk, + // wps->new_psk_len); + os_memcpy(wps->cred.key, hex, wps->new_psk_len * 2); + wps->cred.key_len = wps->new_psk_len * 2; + } + +use_provided: +#ifdef CONFIG_WPS_TESTING + + if (wps_testing_dummy_cred) { + cred = wpabuf_alloc(200); + } else { + cred = NULL; + } + + if (cred) { + struct wps_credential dummy; + wpa_printf(MSG_DEBUG, "WPS: Add dummy credential"); + os_memset(&dummy, 0, sizeof(dummy)); + os_memcpy(dummy.ssid, "dummy", 5); + dummy.ssid_len = 5; + dummy.auth_type = WPS_AUTH_WPA2PSK; + dummy.encr_type = WPS_ENCR_AES; + os_memcpy(dummy.key, "dummy psk", 9); + dummy.key_len = 9; + os_memcpy(dummy.mac_addr, wps->mac_addr_e, ETH_ALEN); + wps_build_credential(cred, &dummy); + wpa_hexdump_buf(MSG_DEBUG, "WPS: Dummy Credential", cred); + + wpabuf_put_be16(msg, ATTR_CRED); + wpabuf_put_be16(msg, wpabuf_len(cred)); + wpabuf_put_buf(msg, cred); + + wpabuf_free(cred); + } + +#endif /* CONFIG_WPS_TESTING */ + + cred = wpabuf_alloc(200); + + if (cred == NULL) { + return -1; + } + + if (wps_build_credential(cred, &wps->cred)) { + wpabuf_free(cred); + return -1; + } + + wpabuf_put_be16(msg, ATTR_CRED); + wpabuf_put_be16(msg, wpabuf_len(cred)); + wpabuf_put_buf(msg, cred); + wpabuf_free(cred); + +skip_cred_build: + + if (wps->wps->registrar->extra_cred) { + wpa_printf(MSG_DEBUG, "WPS: * Credential (pre-configured)"); + wpabuf_put_buf(msg, wps->wps->registrar->extra_cred); + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_build_ap_settings(struct wps_data* wps, struct wpabuf* msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * AP Settings"); + + if (wps_build_credential(msg, &wps->cred)) { + return -1; + } + + return 0; +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_ap_cred(struct wps_data* wps) +{ + struct wpabuf* msg, *plain; + + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + return NULL; + } + + plain = wpabuf_alloc(200); + + if (plain == NULL) { + wpabuf_free(msg); + return NULL; + } + + if (wps_build_ap_settings(wps, plain)) { + wpabuf_free(plain); + wpabuf_free(msg); + return NULL; + } + + wpabuf_put_be16(msg, ATTR_CRED); + wpabuf_put_be16(msg, wpabuf_len(plain)); + wpabuf_put_buf(msg, plain); + wpabuf_free(plain); + + return msg; +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_m2(struct wps_data* wps) +{ + struct wpabuf* msg; + + if (random_get_bytes(wps->nonce_r, WPS_NONCE_LEN) < 0) { + return NULL; + } + + wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce", + wps->nonce_r, WPS_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN); + + wpa_printf(MSG_DEBUG, "WPS: Building Message M2"); + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + return NULL; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_M2) || + wps_build_enrollee_nonce(wps, msg) || + wps_build_registrar_nonce(wps, msg) || + wps_build_uuid_r(wps, msg) || + wps_build_public_key(wps, msg, WPS_CALC_KEY_NORMAL) || + wps_derive_keys(wps) || + wps_build_auth_type_flags(wps, msg) || + wps_build_encr_type_flags(wps, msg) || + wps_build_conn_type_flags(wps, msg) || + wps_build_config_methods_r(wps->wps->registrar, msg) || + wps_build_device_attrs(&wps->wps->dev, msg) || + wps_build_rf_bands(&wps->wps->dev, msg) || + wps_build_assoc_state(wps, msg) || + wps_build_config_error(msg, WPS_CFG_NO_ERROR) || + wps_build_dev_password_id(msg, wps->dev_pw_id) || + wps_build_os_version(&wps->wps->dev, msg) || + wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_authenticator(wps, msg)) { + wpabuf_free(msg); + return NULL; + } + + wps->int_reg = 1; + wps->state = RECV_M3; + return msg; +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_m2d(struct wps_data* wps) +{ + struct wpabuf* msg; + u16 err = wps->config_error; + + wpa_printf(MSG_DEBUG, "WPS: Building Message M2D"); + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + return NULL; + } + + if (wps->wps->ap && wps->wps->ap_setup_locked && + err == WPS_CFG_NO_ERROR) { + err = WPS_CFG_SETUP_LOCKED; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_M2D) || + wps_build_enrollee_nonce(wps, msg) || + wps_build_registrar_nonce(wps, msg) || + wps_build_uuid_r(wps, msg) || + wps_build_auth_type_flags(wps, msg) || + wps_build_encr_type_flags(wps, msg) || + wps_build_conn_type_flags(wps, msg) || + wps_build_config_methods_r(wps->wps->registrar, msg) || + wps_build_device_attrs(&wps->wps->dev, msg) || + wps_build_rf_bands(&wps->wps->dev, msg) || + wps_build_assoc_state(wps, msg) || + wps_build_config_error(msg, err) || + wps_build_os_version(&wps->wps->dev, msg) || + wps_build_wfa_ext(msg, 0, NULL, 0)) { + wpabuf_free(msg); + return NULL; + } + + wps->state = RECV_M2D_ACK; + return msg; +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_m4(struct wps_data* wps) +{ + struct wpabuf* msg, *plain; + + wpa_printf(MSG_DEBUG, "WPS: Building Message M4"); + + wps_derive_psk(wps, wps->dev_password, wps->dev_password_len); + + plain = wpabuf_alloc(200); + + if (plain == NULL) { + return NULL; + } + + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + wpabuf_free(plain); + return NULL; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_M4) || + wps_build_enrollee_nonce(wps, msg) || + wps_build_r_hash(wps, msg) || + wps_build_r_snonce1(wps, plain) || + wps_build_key_wrap_auth(wps, plain) || + wps_build_encr_settings(wps, msg, plain) || + wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_authenticator(wps, msg)) { + wpabuf_free(plain); + wpabuf_free(msg); + return NULL; + } + + wpabuf_free(plain); + + wps->state = RECV_M5; + return msg; +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_m6(struct wps_data* wps) +{ + struct wpabuf* msg, *plain; + + wpa_printf(MSG_DEBUG, "WPS: Building Message M6"); + + plain = wpabuf_alloc(200); + + if (plain == NULL) { + return NULL; + } + + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + wpabuf_free(plain); + return NULL; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_M6) || + wps_build_enrollee_nonce(wps, msg) || + wps_build_r_snonce2(wps, plain) || + wps_build_key_wrap_auth(wps, plain) || + wps_build_encr_settings(wps, msg, plain) || + wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_authenticator(wps, msg)) { + wpabuf_free(plain); + wpabuf_free(msg); + return NULL; + } + + wpabuf_free(plain); + + wps->wps_pin_revealed = 1; + wps->state = RECV_M7; + return msg; +} + + +static struct wpabuf* ICACHE_FLASH_ATTR wps_build_m8(struct wps_data* wps) +{ + struct wpabuf* msg, *plain; + + wpa_printf(MSG_DEBUG, "WPS: Building Message M8"); + + plain = wpabuf_alloc(500); + + if (plain == NULL) { + return NULL; + } + + msg = wpabuf_alloc(1000); + + if (msg == NULL) { + wpabuf_free(plain); + return NULL; + } + + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_M8) || + wps_build_enrollee_nonce(wps, msg) || + ((wps->wps->ap || wps->er) && wps_build_cred(wps, plain)) || + (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) || + wps_build_key_wrap_auth(wps, plain) || + wps_build_encr_settings(wps, msg, plain) || + wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_authenticator(wps, msg)) { + wpabuf_free(plain); + wpabuf_free(msg); + return NULL; + } + + wpabuf_free(plain); + + wps->state = RECV_DONE; + return msg; +} + + +struct wpabuf* ICACHE_FLASH_ATTR wps_registrar_get_msg(struct wps_data* wps, + enum wsc_op_code* op_code) +{ + struct wpabuf* msg; + +#ifdef CONFIG_WPS_UPNP + + if (!wps->int_reg && wps->wps->wps_upnp) { + struct upnp_pending_message* p, *prev = NULL; + + if (wps->ext_reg > 1) { + wps_registrar_free_pending_m2(wps->wps); + } + + p = wps->wps->upnp_msgs; + + /* TODO: check pending message MAC address */ + while (p && p->next) { + prev = p; + p = p->next; + } + + if (p) { + wpa_printf(MSG_DEBUG, "WPS: Use pending message from " + "UPnP"); + + if (prev) { + prev->next = NULL; + } else { + wps->wps->upnp_msgs = NULL; + } + + msg = p->msg; + + switch (p->type) { + case WPS_WSC_ACK: + *op_code = WSC_ACK; + break; + + case WPS_WSC_NACK: + *op_code = WSC_NACK; + break; + + default: + *op_code = WSC_MSG; + break; + } + + os_free(p); + + if (wps->ext_reg == 0) { + wps->ext_reg = 1; + } + + return msg; + } + } + + if (wps->ext_reg) { + wpa_printf(MSG_DEBUG, "WPS: Using external Registrar, but no " + "pending message available"); + return NULL; + } + +#endif /* CONFIG_WPS_UPNP */ + + switch (wps->state) { + case SEND_M2: + if (wps_get_dev_password(wps) < 0) { + msg = wps_build_m2d(wps); + } else { + msg = wps_build_m2(wps); + } + + *op_code = WSC_MSG; + break; + + case SEND_M2D: + msg = wps_build_m2d(wps); + *op_code = WSC_MSG; + break; + + case SEND_M4: + msg = wps_build_m4(wps); + *op_code = WSC_MSG; + break; + + case SEND_M6: + msg = wps_build_m6(wps); + *op_code = WSC_MSG; + break; + + case SEND_M8: + msg = wps_build_m8(wps); + *op_code = WSC_MSG; + break; + + case RECV_DONE: + msg = wps_build_wsc_ack(wps); + *op_code = WSC_ACK; + break; + + case SEND_WSC_NACK: + msg = wps_build_wsc_nack(wps); + *op_code = WSC_NACK; + break; + + default: + wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building " + "a message", wps->state); + msg = NULL; + break; + } + + if (*op_code == WSC_MSG && msg) { + /* Save a copy of the last message for Authenticator derivation + */ + wpabuf_free(wps->last_msg); + wps->last_msg = wpabuf_dup(msg); + } + + return msg; +} + + +static int ICACHE_FLASH_ATTR wps_process_enrollee_nonce(struct wps_data* wps, const u8* e_nonce) +{ + if (e_nonce == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received"); + return -1; + } + + os_memcpy(wps->nonce_e, e_nonce, WPS_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce", + wps->nonce_e, WPS_NONCE_LEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_registrar_nonce(struct wps_data* wps, const u8* r_nonce) +{ + if (r_nonce == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received"); + return -1; + } + + if (os_memcmp(wps->nonce_r, r_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce received"); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_uuid_e(struct wps_data* wps, const u8* uuid_e) +{ + if (uuid_e == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No UUID-E received"); + return -1; + } + + os_memcpy(wps->uuid_e, uuid_e, WPS_UUID_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", wps->uuid_e, WPS_UUID_LEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_dev_password_id(struct wps_data* wps, const u8* pw_id) +{ + if (pw_id == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Device Password ID received"); + return -1; + } + + wps->dev_pw_id = WPA_GET_BE16(pw_id); + wpa_printf(MSG_DEBUG, "WPS: Device Password ID %d", wps->dev_pw_id); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_e_hash1(struct wps_data* wps, const u8* e_hash1) +{ + if (e_hash1 == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No E-Hash1 received"); + return -1; + } + + os_memcpy(wps->peer_hash1, e_hash1, WPS_HASH_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", wps->peer_hash1, WPS_HASH_LEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_e_hash2(struct wps_data* wps, const u8* e_hash2) +{ + if (e_hash2 == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No E-Hash2 received"); + return -1; + } + + os_memcpy(wps->peer_hash2, e_hash2, WPS_HASH_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", wps->peer_hash2, WPS_HASH_LEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_e_snonce1(struct wps_data* wps, const u8* e_snonce1) +{ + u8 hash[SHA256_MAC_LEN]; + const u8* addr[4]; + size_t len[4]; + + if (e_snonce1 == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No E-SNonce1 received"); + return -1; + } + + wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce1", e_snonce1, + WPS_SECRET_NONCE_LEN); + + /* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */ + addr[0] = e_snonce1; + len[0] = WPS_SECRET_NONCE_LEN; + addr[1] = wps->psk1; + len[1] = WPS_PSK_LEN; + addr[2] = wpabuf_head(wps->dh_pubkey_e); + len[2] = wpabuf_len(wps->dh_pubkey_e); + addr[3] = wpabuf_head(wps->dh_pubkey_r); + len[3] = wpabuf_len(wps->dh_pubkey_r); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + + if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does " + "not match with the pre-committed value"); + wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; + wps_pwd_auth_fail_event(wps->wps, 0, 1); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the first " + "half of the device password"); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_e_snonce2(struct wps_data* wps, const u8* e_snonce2) +{ + u8 hash[SHA256_MAC_LEN]; + const u8* addr[4]; + size_t len[4]; + + if (e_snonce2 == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No E-SNonce2 received"); + return -1; + } + + wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce2", e_snonce2, + WPS_SECRET_NONCE_LEN); + + /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */ + addr[0] = e_snonce2; + len[0] = WPS_SECRET_NONCE_LEN; + addr[1] = wps->psk2; + len[1] = WPS_PSK_LEN; + addr[2] = wpabuf_head(wps->dh_pubkey_e); + len[2] = wpabuf_len(wps->dh_pubkey_e); + addr[3] = wpabuf_head(wps->dh_pubkey_r); + len[3] = wpabuf_len(wps->dh_pubkey_r); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + + if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does " + "not match with the pre-committed value"); +#ifdef CONFIG_WPS_PIN + wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e); +#endif + wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; + wps_pwd_auth_fail_event(wps->wps, 0, 2); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the second " + "half of the device password"); + wps->wps_pin_revealed = 0; +#ifdef CONFIG_WPS_PIN + wps_registrar_unlock_pin(wps->wps->registrar, wps->uuid_e); + + /* + * In case wildcard PIN is used and WPS handshake succeeds in the first + * attempt, wps_registrar_unlock_pin() would not free the PIN, so make + * sure the PIN gets invalidated here. + */ + wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e); +#endif + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_mac_addr(struct wps_data* wps, const u8* mac_addr) +{ + if (mac_addr == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No MAC Address received"); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: Enrollee MAC Address " MACSTR, + MAC2STR(mac_addr)); + os_memcpy(wps->mac_addr_e, mac_addr, ETH_ALEN); + os_memcpy(wps->peer_dev.mac_addr, mac_addr, ETH_ALEN); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_pubkey(struct wps_data* wps, const u8* pk, + size_t pk_len) +{ + if (pk == NULL || pk_len == 0) { + wpa_printf(MSG_DEBUG, "WPS: No Public Key received"); + return -1; + } + + wpabuf_free(wps->dh_pubkey_e); + wps->dh_pubkey_e = wpabuf_alloc_copy(pk, pk_len); + + if (wps->dh_pubkey_e == NULL) { + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_auth_type_flags(struct wps_data* wps, const u8* auth) +{ + u16 auth_types; + + if (auth == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Authentication Type flags " + "received"); + return -1; + } + + auth_types = WPA_GET_BE16(auth); + + wpa_printf(MSG_DEBUG, "WPS: Enrollee Authentication Type flags 0x%x", + auth_types); + wps->auth_type = wps->wps->auth_types & auth_types; + + if (wps->auth_type == 0) { + wpa_printf(MSG_DEBUG, "WPS: No match in supported " + "authentication types (own 0x%x Enrollee 0x%x)", + wps->wps->auth_types, auth_types); +#ifdef WPS_WORKAROUNDS + /* + * Some deployed implementations seem to advertise incorrect + * information in this attribute. For example, Linksys WRT350N + * seems to have a byteorder bug that breaks this negotiation. + * In order to interoperate with existing implementations, + * assume that the Enrollee supports everything we do. + */ + wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee " + "does not advertise supported authentication types " + "correctly"); + wps->auth_type = wps->wps->auth_types; +#else /* WPS_WORKAROUNDS */ + return -1; +#endif /* WPS_WORKAROUNDS */ + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_encr_type_flags(struct wps_data* wps, const u8* encr) +{ + u16 encr_types; + + if (encr == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Encryption Type flags " + "received"); + return -1; + } + + encr_types = WPA_GET_BE16(encr); + + wpa_printf(MSG_DEBUG, "WPS: Enrollee Encryption Type flags 0x%x", + encr_types); + wps->encr_type = wps->wps->encr_types & encr_types; + + if (wps->encr_type == 0) { + wpa_printf(MSG_DEBUG, "WPS: No match in supported " + "encryption types (own 0x%x Enrollee 0x%x)", + wps->wps->encr_types, encr_types); +#ifdef WPS_WORKAROUNDS + /* + * Some deployed implementations seem to advertise incorrect + * information in this attribute. For example, Linksys WRT350N + * seems to have a byteorder bug that breaks this negotiation. + * In order to interoperate with existing implementations, + * assume that the Enrollee supports everything we do. + */ + wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee " + "does not advertise supported encryption types " + "correctly"); + wps->encr_type = wps->wps->encr_types; +#else /* WPS_WORKAROUNDS */ + return -1; +#endif /* WPS_WORKAROUNDS */ + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_conn_type_flags(struct wps_data* wps, const u8* conn) +{ + if (conn == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Connection Type flags " + "received"); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: Enrollee Connection Type flags 0x%x", + *conn); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_config_methods(struct wps_data* wps, const u8* methods) +{ + u16 m; + + if (methods == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Config Methods received"); + return -1; + } + + m = WPA_GET_BE16(methods); + + wpa_printf(MSG_DEBUG, "WPS: Enrollee Config Methods 0x%x" + "%s%s%s%s%s%s%s%s%s", m, + m & WPS_CONFIG_USBA ? " [USBA]" : "", + m & WPS_CONFIG_ETHERNET ? " [Ethernet]" : "", + m & WPS_CONFIG_LABEL ? " [Label]" : "", + m & WPS_CONFIG_DISPLAY ? " [Display]" : "", + m & WPS_CONFIG_EXT_NFC_TOKEN ? " [Ext NFC Token]" : "", + m & WPS_CONFIG_INT_NFC_TOKEN ? " [Int NFC Token]" : "", + m & WPS_CONFIG_NFC_INTERFACE ? " [NFC]" : "", + m & WPS_CONFIG_PUSHBUTTON ? " [PBC]" : "", + m & WPS_CONFIG_KEYPAD ? " [Keypad]" : ""); + + if (!(m & WPS_CONFIG_DISPLAY) && !wps->use_psk_key) { + /* + * The Enrollee does not have a display so it is unlikely to be + * able to show the passphrase to a user and as such, could + * benefit from receiving PSK to reduce key derivation time. + */ + wpa_printf(MSG_DEBUG, "WPS: Prefer PSK format key due to " + "Enrollee not supporting display"); + wps->use_psk_key = 1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_wps_state(struct wps_data* wps, const u8* state) +{ + if (state == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Wi-Fi Protected Setup State " + "received"); + return -1; + } + + wpa_printf(MSG_DEBUG, "WPS: Enrollee Wi-Fi Protected Setup State %d", + *state); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_assoc_state(struct wps_data* wps, const u8* assoc) +{ + u16 a; + + if (assoc == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Association State received"); + return -1; + } + + a = WPA_GET_BE16(assoc); + wpa_printf(MSG_DEBUG, "WPS: Enrollee Association State %d", a); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_process_config_error(struct wps_data* wps, const u8* err) +{ + u16 e; + + if (err == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Configuration Error received"); + return -1; + } + + e = WPA_GET_BE16(err); + wpa_printf(MSG_DEBUG, "WPS: Enrollee Configuration Error %d", e); + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_registrar_p2p_dev_addr_match(struct wps_data* wps) +{ +#ifdef CONFIG_P2P + struct wps_registrar* reg = wps->wps->registrar; + + if (is_zero_ether_addr(reg->p2p_dev_addr)) { + return 1; /* no filtering in use */ + } + + if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: No match on P2P Device Address " + "filtering for PBC: expected " MACSTR " was " + MACSTR " - indicate PBC session overlap", + MAC2STR(reg->p2p_dev_addr), + MAC2STR(wps->p2p_dev_addr)); + return 0; + } + +#endif /* CONFIG_P2P */ + return 1; +} + + +static int ICACHE_FLASH_ATTR wps_registrar_skip_overlap(struct wps_data* wps) +{ +#ifdef CONFIG_P2P + struct wps_registrar* reg = wps->wps->registrar; + + if (is_zero_ether_addr(reg->p2p_dev_addr)) { + return 0; /* no specific Enrollee selected */ + } + + if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) == 0) { + wpa_printf(MSG_DEBUG, "WPS: Skip PBC overlap due to selected " + "Enrollee match"); + return 1; + } + +#endif /* CONFIG_P2P */ + return 0; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_m1(struct wps_data* wps, + struct wps_parse_attr* attr) +{ + wpa_printf(MSG_DEBUG, "WPS: Received M1"); + + if (wps->state != RECV_M1) { + wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " + "receiving M1", wps->state); + return WPS_FAILURE; + } + + if (wps_process_uuid_e(wps, attr->uuid_e) || + wps_process_mac_addr(wps, attr->mac_addr) || + wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || + wps_process_pubkey(wps, attr->public_key, attr->public_key_len) || + wps_process_auth_type_flags(wps, attr->auth_type_flags) || + wps_process_encr_type_flags(wps, attr->encr_type_flags) || + wps_process_conn_type_flags(wps, attr->conn_type_flags) || + wps_process_config_methods(wps, attr->config_methods) || + wps_process_wps_state(wps, attr->wps_state) || + wps_process_device_attrs(&wps->peer_dev, attr) || + wps_process_rf_bands(&wps->peer_dev, attr->rf_bands) || + wps_process_assoc_state(wps, attr->assoc_state) || + wps_process_dev_password_id(wps, attr->dev_password_id) || + wps_process_config_error(wps, attr->config_error) || + wps_process_os_version(&wps->peer_dev, attr->os_version)) { + return WPS_FAILURE; + } + + if (wps->dev_pw_id < 0x10 && + wps->dev_pw_id != DEV_PW_DEFAULT && + wps->dev_pw_id != DEV_PW_USER_SPECIFIED && + wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED && + wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED && + (wps->dev_pw_id != DEV_PW_PUSHBUTTON || + !wps->wps->registrar->pbc)) { + wpa_printf(MSG_DEBUG, "WPS: Unsupported Device Password ID %d", + wps->dev_pw_id); + wps->state = SEND_M2D; + return WPS_CONTINUE; + } + +#ifdef CONFIG_WPS_NFC + + if (wps->dev_pw_id >= 0x10) { + struct wps_nfc_pw_token* token; + const u8* addr[1]; + u8 hash[WPS_HASH_LEN]; + + token = wps_get_nfc_pw_token( + &wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id); + + if (token) { + wpa_printf(MSG_DEBUG, "WPS: Found matching NFC " + "Password Token"); + dl_list_del(&token->list); + wps->nfc_pw_token = token; + + addr[0] = attr->public_key; + sha256_vector(1, addr, &attr->public_key_len, hash); + + if (os_memcmp(hash, wps->nfc_pw_token->pubkey_hash, + WPS_OOB_PUBKEY_HASH_LEN) != 0) { + wpa_printf(MSG_ERROR, "WPS: Public Key hash " + "mismatch"); + return WPS_FAILURE; + } + } + } + +#endif /* CONFIG_WPS_NFC */ + + if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) { + if ((wps->wps->registrar->force_pbc_overlap || + wps_registrar_pbc_overlap(wps->wps->registrar, + wps->mac_addr_e, wps->uuid_e) || + !wps_registrar_p2p_dev_addr_match(wps)) && + !wps_registrar_skip_overlap(wps)) { + wpa_printf(MSG_DEBUG, "WPS: PBC overlap - deny PBC " + "negotiation"); + wps->state = SEND_M2D; + wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED; + wps_pbc_overlap_event(wps->wps); + wps_fail_event(wps->wps, WPS_M1, + WPS_CFG_MULTIPLE_PBC_DETECTED, + WPS_EI_NO_ERROR); + wps->wps->registrar->force_pbc_overlap = 1; + return WPS_CONTINUE; + } + + wps_registrar_add_pbc_session(wps->wps->registrar, + wps->mac_addr_e, wps->uuid_e); + wps->pbc = 1; + } + +#ifdef WPS_WORKAROUNDS + + /* + * It looks like Mac OS X 10.6.3 and 10.6.4 do not like Network Key in + * passphrase format. To avoid interop issues, force PSK format to be + * used. + */ + if (!wps->use_psk_key && + wps->peer_dev.manufacturer && + os_strncmp(wps->peer_dev.manufacturer, "Apple ", 6) == 0 && + wps->peer_dev.model_name && + os_strcmp(wps->peer_dev.model_name, "AirPort") == 0) { + wpa_printf(MSG_DEBUG, "WPS: Workaround - Force Network Key in " + "PSK format"); + wps->use_psk_key = 1; + } + +#endif /* WPS_WORKAROUNDS */ + + wps->state = SEND_M2; + return WPS_CONTINUE; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_m3(struct wps_data* wps, + const struct wpabuf* msg, + struct wps_parse_attr* attr) +{ + wpa_printf(MSG_DEBUG, "WPS: Received M3"); + + if (wps->state != RECV_M3) { + wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " + "receiving M3", wps->state); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + if (wps->pbc && wps->wps->registrar->force_pbc_overlap && + !wps_registrar_skip_overlap(wps)) { + wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC " + "session overlap"); + wps->state = SEND_WSC_NACK; + wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED; + return WPS_CONTINUE; + } + + if (wps_process_registrar_nonce(wps, attr->registrar_nonce) || + wps_process_authenticator(wps, attr->authenticator, msg) || + wps_process_e_hash1(wps, attr->e_hash1) || + wps_process_e_hash2(wps, attr->e_hash2)) { + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + wps->state = SEND_M4; + return WPS_CONTINUE; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_m5(struct wps_data* wps, + const struct wpabuf* msg, + struct wps_parse_attr* attr) +{ + struct wpabuf* decrypted; + struct wps_parse_attr eattr; + + wpa_printf(MSG_DEBUG, "WPS: Received M5"); + + if (wps->state != RECV_M5) { + wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " + "receiving M5", wps->state); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + if (wps->pbc && wps->wps->registrar->force_pbc_overlap && + !wps_registrar_skip_overlap(wps)) { + wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC " + "session overlap"); + wps->state = SEND_WSC_NACK; + wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED; + return WPS_CONTINUE; + } + + if (wps_process_registrar_nonce(wps, attr->registrar_nonce) || + wps_process_authenticator(wps, attr->authenticator, msg)) { + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, + attr->encr_settings_len); + + if (decrypted == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " + "Settings attribute"); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + if (wps_validate_m5_encr(decrypted, attr->version2 != NULL) < 0) { + wpabuf_free(decrypted); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " + "attribute"); + + if (wps_parse_msg(decrypted, &eattr) < 0 || + wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || + wps_process_e_snonce1(wps, eattr.e_snonce1)) { + wpabuf_free(decrypted); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + wpabuf_free(decrypted); + + wps->state = SEND_M6; + return WPS_CONTINUE; +} + + +static void ICACHE_FLASH_ATTR wps_sta_cred_cb(struct wps_data* wps) +{ + /* + * Update credential to only include a single authentication and + * encryption type in case the AP configuration includes more than one + * option. + */ + if (wps->cred.auth_type & WPS_AUTH_WPA2PSK) { + wps->cred.auth_type = WPS_AUTH_WPA2PSK; + } else if (wps->cred.auth_type & WPS_AUTH_WPAPSK) { + wps->cred.auth_type = WPS_AUTH_WPAPSK; + } + + if (wps->cred.encr_type & WPS_ENCR_AES) { + wps->cred.encr_type = WPS_ENCR_AES; + } else if (wps->cred.encr_type & WPS_ENCR_TKIP) { + wps->cred.encr_type = WPS_ENCR_TKIP; + } + + wpa_printf(MSG_DEBUG, "WPS: Update local configuration based on the " + "AP configuration"); + + if (wps->wps->cred_cb) { + wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred); + } +} + + +static void ICACHE_FLASH_ATTR wps_cred_update(struct wps_credential* dst, + struct wps_credential* src) +{ + os_memcpy(dst->ssid, src->ssid, sizeof(dst->ssid)); + dst->ssid_len = src->ssid_len; + dst->auth_type = src->auth_type; + dst->encr_type = src->encr_type; + dst->key_idx = src->key_idx; + os_memcpy(dst->key, src->key, sizeof(dst->key)); + dst->key_len = src->key_len; +} + + +static int ICACHE_FLASH_ATTR wps_process_ap_settings_r(struct wps_data* wps, + struct wps_parse_attr* attr) +{ + struct wpabuf* msg; + + if (wps->wps->ap || wps->er) { + return 0; + } + + /* AP Settings Attributes in M7 when Enrollee is an AP */ + if (wps_process_ap_settings(attr, &wps->cred) < 0) { + return -1; + } + + wpa_printf(MSG_INFO, "WPS: Received old AP configuration from AP"); + + if (wps->new_ap_settings) { + wpa_printf(MSG_INFO, "WPS: Update AP configuration based on " + "new settings"); + wps_cred_update(&wps->cred, wps->new_ap_settings); + return 0; + } else { +#ifdef CONFIG_WPS_PIN + /* + * Use the AP PIN only to receive the current AP settings, not + * to reconfigure the AP. + */ + + /* + * Clear selected registrar here since we do not get to + * WSC_Done in this protocol run. + */ + wps_registrar_pin_completed(wps->wps->registrar); +#endif + msg = wps_build_ap_cred(wps); + + if (msg == NULL) { + return -1; + } + + wps->cred.cred_attr = wpabuf_head(msg); + wps->cred.cred_attr_len = wpabuf_len(msg); + + if (wps->ap_settings_cb) { + wps->ap_settings_cb(wps->ap_settings_cb_ctx, + &wps->cred); + wpabuf_free(msg); + return 1; + } + + wps_sta_cred_cb(wps); + + wps->cred.cred_attr = NULL; + wps->cred.cred_attr_len = 0; + wpabuf_free(msg); + + return 1; + } +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_m7(struct wps_data* wps, + const struct wpabuf* msg, + struct wps_parse_attr* attr) +{ + struct wpabuf* decrypted; + struct wps_parse_attr eattr; + + wpa_printf(MSG_DEBUG, "WPS: Received M7"); + + if (wps->state != RECV_M7) { + wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " + "receiving M7", wps->state); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + if (wps->pbc && wps->wps->registrar->force_pbc_overlap && + !wps_registrar_skip_overlap(wps)) { + wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC " + "session overlap"); + wps->state = SEND_WSC_NACK; + wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED; + return WPS_CONTINUE; + } + + if (wps_process_registrar_nonce(wps, attr->registrar_nonce) || + wps_process_authenticator(wps, attr->authenticator, msg)) { + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, + attr->encr_settings_len); + + if (decrypted == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt Encrypted " + "Settings attribute"); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er, + attr->version2 != NULL) < 0) { + wpabuf_free(decrypted); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " + "attribute"); + + if (wps_parse_msg(decrypted, &eattr) < 0 || + wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || + wps_process_e_snonce2(wps, eattr.e_snonce2) || + wps_process_ap_settings_r(wps, &eattr)) { + wpabuf_free(decrypted); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + wpabuf_free(decrypted); + + wps->state = SEND_M8; + return WPS_CONTINUE; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_wsc_msg(struct wps_data* wps, + const struct wpabuf* msg) +{ + struct wps_parse_attr attr; + enum wps_process_res ret = WPS_CONTINUE; + + wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG"); + + if (wps_parse_msg(msg, &attr) < 0) { + return WPS_FAILURE; + } + + if (attr.msg_type == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); + wps->state = SEND_WSC_NACK; + return WPS_CONTINUE; + } + + if (*attr.msg_type != WPS_M1 && + (attr.registrar_nonce == NULL || + os_memcmp(wps->nonce_r, attr.registrar_nonce, + WPS_NONCE_LEN) != 0)) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); + return WPS_FAILURE; + } + + switch (*attr.msg_type) { + case WPS_M1: + if (wps_validate_m1(msg) < 0) { + return WPS_FAILURE; + } + +#ifdef CONFIG_WPS_UPNP + + if (wps->wps->wps_upnp && attr.mac_addr) { + /* Remove old pending messages when starting new run */ + wps_free_pending_msgs(wps->wps->upnp_msgs); + wps->wps->upnp_msgs = NULL; + + upnp_wps_device_send_wlan_event( + wps->wps->wps_upnp, attr.mac_addr, + UPNP_WPS_WLANEVENT_TYPE_EAP, msg); + } + +#endif /* CONFIG_WPS_UPNP */ + ret = wps_process_m1(wps, &attr); + break; + + case WPS_M3: + if (wps_validate_m3(msg) < 0) { + return WPS_FAILURE; + } + + ret = wps_process_m3(wps, msg, &attr); + + if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) + wps_fail_event(wps->wps, WPS_M3, wps->config_error, + wps->error_indication); + + break; + + case WPS_M5: + if (wps_validate_m5(msg) < 0) { + return WPS_FAILURE; + } + + ret = wps_process_m5(wps, msg, &attr); + + if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) + wps_fail_event(wps->wps, WPS_M5, wps->config_error, + wps->error_indication); + + break; + + case WPS_M7: + if (wps_validate_m7(msg) < 0) { + return WPS_FAILURE; + } + + ret = wps_process_m7(wps, msg, &attr); + + if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) + wps_fail_event(wps->wps, WPS_M7, wps->config_error, + wps->error_indication); + + break; + + default: + wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d", + *attr.msg_type); + return WPS_FAILURE; + } + + if (ret == WPS_CONTINUE) { + /* Save a copy of the last message for Authenticator derivation + */ + wpabuf_free(wps->last_msg); + wps->last_msg = wpabuf_dup(msg); + } + + return ret; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_wsc_ack(struct wps_data* wps, + const struct wpabuf* msg) +{ + struct wps_parse_attr attr; + + wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK"); + + if (wps_parse_msg(msg, &attr) < 0) { + return WPS_FAILURE; + } + + if (attr.msg_type == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); + return WPS_FAILURE; + } + + if (*attr.msg_type != WPS_WSC_ACK) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", + *attr.msg_type); + return WPS_FAILURE; + } + +#ifdef CONFIG_WPS_UPNP + + if (wps->wps->wps_upnp && wps->ext_reg && wps->state == RECV_M2D_ACK && + upnp_wps_subscribers(wps->wps->wps_upnp)) { + if (wps->wps->upnp_msgs) { + return WPS_CONTINUE; + } + + wpa_printf(MSG_DEBUG, "WPS: Wait for response from an " + "external Registrar"); + return WPS_PENDING; + } + +#endif /* CONFIG_WPS_UPNP */ + + if (attr.registrar_nonce == NULL || + os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); + return WPS_FAILURE; + } + + if (attr.enrollee_nonce == NULL || + os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); + return WPS_FAILURE; + } + + if (wps->state == RECV_M2D_ACK) { +#ifdef CONFIG_WPS_UPNP + + if (wps->wps->wps_upnp && + upnp_wps_subscribers(wps->wps->wps_upnp)) { + if (wps->wps->upnp_msgs) { + return WPS_CONTINUE; + } + + if (wps->ext_reg == 0) { + wps->ext_reg = 1; + } + + wpa_printf(MSG_DEBUG, "WPS: Wait for response from an " + "external Registrar"); + return WPS_PENDING; + } + +#endif /* CONFIG_WPS_UPNP */ + + wpa_printf(MSG_DEBUG, "WPS: No more registrars available - " + "terminate negotiation"); + } + + return WPS_FAILURE; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_wsc_nack(struct wps_data* wps, + const struct wpabuf* msg) +{ + struct wps_parse_attr attr; + int old_state; + u16 config_error; + + wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK"); + + old_state = wps->state; + wps->state = SEND_WSC_NACK; + + if (wps_parse_msg(msg, &attr) < 0) { + return WPS_FAILURE; + } + + if (attr.msg_type == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); + return WPS_FAILURE; + } + + if (*attr.msg_type != WPS_WSC_NACK) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", + *attr.msg_type); + return WPS_FAILURE; + } + +#ifdef CONFIG_WPS_UPNP + + if (wps->wps->wps_upnp && wps->ext_reg) { + wpa_printf(MSG_DEBUG, "WPS: Negotiation using external " + "Registrar terminated by the Enrollee"); + return WPS_FAILURE; + } + +#endif /* CONFIG_WPS_UPNP */ + + if (attr.registrar_nonce == NULL || + os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); + return WPS_FAILURE; + } + + if (attr.enrollee_nonce == NULL || + os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); + return WPS_FAILURE; + } + + if (attr.config_error == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute " + "in WSC_NACK"); + return WPS_FAILURE; + } + + config_error = WPA_GET_BE16(attr.config_error); + wpa_printf(MSG_DEBUG, "WPS: Enrollee terminated negotiation with " + "Configuration Error %d", config_error); + + switch (old_state) { + case RECV_M3: + wps_fail_event(wps->wps, WPS_M2, config_error, + wps->error_indication); + break; + + case RECV_M5: + wps_fail_event(wps->wps, WPS_M4, config_error, + wps->error_indication); + break; + + case RECV_M7: + wps_fail_event(wps->wps, WPS_M6, config_error, + wps->error_indication); + break; + + case RECV_DONE: + wps_fail_event(wps->wps, WPS_M8, config_error, + wps->error_indication); + break; + + default: + break; + } + + return WPS_FAILURE; +} + + +static enum wps_process_res ICACHE_FLASH_ATTR wps_process_wsc_done(struct wps_data* wps, + const struct wpabuf* msg) +{ + struct wps_parse_attr attr; + + wpa_printf(MSG_DEBUG, "WPS: Received WSC_Done"); + + //if (wps->state != RECV_DONE && + // (!wps->wps->wps_upnp || !wps->ext_reg)) + if (wps->state != RECV_DONE && (!wps->ext_reg)) { + wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " + "receiving WSC_Done", wps->state); + return WPS_FAILURE; + } + + if (wps_parse_msg(msg, &attr) < 0) { + return WPS_FAILURE; + } + + if (attr.msg_type == NULL) { + wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); + return WPS_FAILURE; + } + + if (*attr.msg_type != WPS_WSC_DONE) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", + *attr.msg_type); + return WPS_FAILURE; + } + +#ifdef CONFIG_WPS_UPNP + + if (wps->wps->wps_upnp && wps->ext_reg) { + wpa_printf(MSG_DEBUG, "WPS: Negotiation using external " + "Registrar completed successfully"); + wps_device_store(wps->wps->registrar, &wps->peer_dev, + wps->uuid_e); + return WPS_DONE; + } + +#endif /* CONFIG_WPS_UPNP */ + + if (attr.registrar_nonce == NULL || + os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); + return WPS_FAILURE; + } + + if (attr.enrollee_nonce == NULL || + os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); + return WPS_FAILURE; + } + + wpa_printf(MSG_DEBUG, "WPS: Negotiation completed successfully"); + wps_device_store(wps->wps->registrar, &wps->peer_dev, + wps->uuid_e); + + if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->new_psk && + wps->wps->ap && !wps->wps->registrar->disable_auto_conf) { + struct wps_credential cred; + + wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based " + "on first Enrollee connection"); + + os_memset(&cred, 0, sizeof(cred)); + os_memcpy(cred.ssid, wps->wps->ssid, wps->wps->ssid_len); + cred.ssid_len = wps->wps->ssid_len; + cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK; + cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES; + os_memcpy(cred.key, wps->new_psk, wps->new_psk_len); + cred.key_len = wps->new_psk_len; + + wps->wps->wps_state = WPS_STATE_CONFIGURED; + wpa_hexdump_ascii_key(MSG_DEBUG, + "WPS: Generated random passphrase", + wps->new_psk, wps->new_psk_len); + + if (wps->wps->cred_cb) { + wps->wps->cred_cb(wps->wps->cb_ctx, &cred); + } + + os_free(wps->new_psk); + wps->new_psk = NULL; + } + + if (!wps->wps->ap && !wps->er) { + wps_sta_cred_cb(wps); + } + + if (wps->new_psk) { + if (wps_cb_new_psk(wps->wps->registrar, wps->mac_addr_e, + wps->new_psk, wps->new_psk_len)) { + wpa_printf(MSG_DEBUG, "WPS: Failed to configure the " + "new PSK"); + } + + os_free(wps->new_psk); + wps->new_psk = NULL; + } + + wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e, + wps->dev_password, wps->dev_password_len); + + if (wps->pbc) { + wps_registrar_remove_pbc_session(wps->wps->registrar, + wps->uuid_e, + wps->p2p_dev_addr); + wps_registrar_pbc_completed(wps->wps->registrar); + os_get_time(&wps->wps->registrar->pbc_ignore_start); + os_memcpy(wps->wps->registrar->pbc_ignore_uuid, wps->uuid_e, + WPS_UUID_LEN); + } else { +#ifdef CONFIG_WPS_PIN + wps_registrar_pin_completed(wps->wps->registrar); +#endif + } + + /* TODO: maintain AuthorizedMACs somewhere separately for each ER and + * merge them into APs own list.. */ + + wps_success_event(wps->wps); + + return WPS_DONE; +} + + +enum wps_process_res ICACHE_FLASH_ATTR wps_registrar_process_msg(struct wps_data* wps, + enum wsc_op_code op_code, + const struct wpabuf* msg) +{ + enum wps_process_res ret; + + wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu " + "op_code=%d)", + (unsigned long) wpabuf_len(msg), op_code); + +#ifdef CONFIG_WPS_UPNP + + if (wps->wps->wps_upnp && op_code == WSC_MSG && wps->ext_reg == 1) { + struct wps_parse_attr attr; + + if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type && + *attr.msg_type == WPS_M3) { + wps->ext_reg = 2; /* past M2/M2D phase */ + } + } + + if (wps->ext_reg > 1) { + wps_registrar_free_pending_m2(wps->wps); + } + + if (wps->wps->wps_upnp && wps->ext_reg && + wps->wps->upnp_msgs == NULL && + (op_code == WSC_MSG || op_code == WSC_Done || op_code == WSC_NACK)) { + struct wps_parse_attr attr; + int type; + + if (wps_parse_msg(msg, &attr) < 0 || attr.msg_type == NULL) { + type = -1; + } else { + type = *attr.msg_type; + } + + wpa_printf(MSG_DEBUG, "WPS: Sending received message (type %d)" + " to external Registrar for processing", type); + upnp_wps_device_send_wlan_event(wps->wps->wps_upnp, + wps->mac_addr_e, + UPNP_WPS_WLANEVENT_TYPE_EAP, + msg); + + if (op_code == WSC_MSG) { + return WPS_PENDING; + } + } else if (wps->wps->wps_upnp && wps->ext_reg && op_code == WSC_MSG) { + wpa_printf(MSG_DEBUG, "WPS: Skip internal processing - using " + "external Registrar"); + return WPS_CONTINUE; + } + +#endif /* CONFIG_WPS_UPNP */ + + switch (op_code) { + case WSC_MSG: + return wps_process_wsc_msg(wps, msg); + + case WSC_ACK: + if (wps_validate_wsc_ack(msg) < 0) { + return WPS_FAILURE; + } + + return wps_process_wsc_ack(wps, msg); + + case WSC_NACK: + if (wps_validate_wsc_nack(msg) < 0) { + return WPS_FAILURE; + } + + return wps_process_wsc_nack(wps, msg); + + case WSC_Done: + if (wps_validate_wsc_done(msg) < 0) { + return WPS_FAILURE; + } + + ret = wps_process_wsc_done(wps, msg); + + if (ret == WPS_FAILURE) { + wps->state = SEND_WSC_NACK; + wps_fail_event(wps->wps, WPS_WSC_DONE, + wps->config_error, + wps->error_indication); + } + + return ret; + + default: + wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code); + return WPS_FAILURE; + } +} + + +int ICACHE_FLASH_ATTR wps_registrar_update_ie(struct wps_registrar* reg) +{ + return wps_set_ie(reg); +} + + +//static void ICACHE_FLASH_ATTR wps_registrar_set_selected_timeout(void *eloop_ctx, +// void *timeout_ctx) +#if 0 +static void ICACHE_FLASH_ATTR wps_registrar_set_selected_timeout(void* eloop_ctx) +{ + struct wps_registrar* reg = eloop_ctx; + + wpa_printf(MSG_DEBUG, "WPS: Selected Registrar timeout - " + "unselect internal Registrar"); + reg->selected_registrar = 0; + reg->pbc = 0; + wps_registrar_selected_registrar_changed(reg); +} +#endif + +#ifdef CONFIG_WPS_UPNP +static void ICACHE_FLASH_ATTR wps_registrar_sel_reg_add(struct wps_registrar* reg, + struct subscription* s) +{ + int i, j; + wpa_printf(MSG_DEBUG, "WPS: External Registrar selected (dev_pw_id=%d " + "config_methods=0x%x)", + s->dev_password_id, s->config_methods); + reg->sel_reg_union = 1; + + if (reg->sel_reg_dev_password_id_override != DEV_PW_PUSHBUTTON) { + reg->sel_reg_dev_password_id_override = s->dev_password_id; + } + + if (reg->sel_reg_config_methods_override == -1) { + reg->sel_reg_config_methods_override = 0; + } + + reg->sel_reg_config_methods_override |= s->config_methods; + + for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) + if (is_zero_ether_addr(reg->authorized_macs_union[i])) { + break; + } + + for (j = 0; i < WPS_MAX_AUTHORIZED_MACS && j < WPS_MAX_AUTHORIZED_MACS; + j++) { + if (is_zero_ether_addr(s->authorized_macs[j])) { + break; + } + + wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC into union: " + MACSTR, MAC2STR(s->authorized_macs[j])); + os_memcpy(reg->authorized_macs_union[i], + s->authorized_macs[j], ETH_ALEN); + i++; + } + + wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union", + (u8*) reg->authorized_macs_union, + sizeof(reg->authorized_macs_union)); +} +#endif /* CONFIG_WPS_UPNP */ + + +static void ICACHE_FLASH_ATTR wps_registrar_sel_reg_union(struct wps_registrar* reg) +{ +#ifdef CONFIG_WPS_UPNP + struct subscription* s; + + if (reg->wps->wps_upnp == NULL) { + return; + } + + dl_list_for_each(s, ®->wps->wps_upnp->subscriptions, + struct subscription, list) { + struct subscr_addr* sa; + sa = dl_list_first(&s->addr_list, struct subscr_addr, list); + + if (sa) { + wpa_printf(MSG_DEBUG, "WPS: External Registrar %s:%d", + inet_ntoa(sa->saddr.sin_addr), + ntohs(sa->saddr.sin_port)); + } + + if (s->selected_registrar) { + wps_registrar_sel_reg_add(reg, s); + } else + wpa_printf(MSG_DEBUG, "WPS: External Registrar not " + "selected"); + } +#endif /* CONFIG_WPS_UPNP */ +} + + +/** + * wps_registrar_selected_registrar_changed - SetSelectedRegistrar change + * @reg: Registrar data from wps_registrar_init() + * + * This function is called when selected registrar state changes, e.g., when an + * AP receives a SetSelectedRegistrar UPnP message. + */ +void ICACHE_FLASH_ATTR wps_registrar_selected_registrar_changed(struct wps_registrar* reg) +{ + wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed"); + + reg->sel_reg_union = reg->selected_registrar; + reg->sel_reg_dev_password_id_override = -1; + reg->sel_reg_config_methods_override = -1; + os_memcpy(reg->authorized_macs_union, reg->authorized_macs, + WPS_MAX_AUTHORIZED_MACS * ETH_ALEN); + wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union (start with own)", + (u8*) reg->authorized_macs_union, + sizeof(reg->authorized_macs_union)); + + if (reg->selected_registrar) { + u16 methods; + + methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; +#ifdef CONFIG_WPS2 + methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | + WPS_CONFIG_PHY_PUSHBUTTON); +#endif /* CONFIG_WPS2 */ + + if (reg->pbc) { + reg->sel_reg_dev_password_id_override = + DEV_PW_PUSHBUTTON; + wps_set_pushbutton(&methods, reg->wps->config_methods); + } + + wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected " + "(pbc=%d)", reg->pbc); + reg->sel_reg_config_methods_override = methods; + } else { + wpa_printf(MSG_DEBUG, "WPS: Internal Registrar not selected"); + } + + wps_registrar_sel_reg_union(reg); + + wps_set_ie(reg); + wps_cb_set_sel_reg(reg); +} + + +int ICACHE_FLASH_ATTR wps_registrar_get_info(struct wps_registrar* reg, const u8* addr, + char* buf, size_t buflen) +{ + struct wps_registrar_device* d; + int len = 0, ret; + char uuid[40]; + char devtype[WPS_DEV_TYPE_BUFSIZE]; + + d = wps_device_get(reg, addr); + + if (d == NULL) { + return 0; + } + + if (uuid_bin2str(d->uuid, uuid, sizeof(uuid))) { + return 0; + } + + ret = snprintf(buf + len, buflen - len, + "wpsUuid=%s\n" + "wpsPrimaryDeviceType=%s\n" + "wpsDeviceName=%s\n" + "wpsManufacturer=%s\n" + "wpsModelName=%s\n" + "wpsModelNumber=%s\n" + "wpsSerialNumber=%s\n", + uuid, + wps_dev_type_bin2str(d->dev.pri_dev_type, devtype, + sizeof(devtype)), + d->dev.device_name ? d->dev.device_name : "", + d->dev.manufacturer ? d->dev.manufacturer : "", + d->dev.model_name ? d->dev.model_name : "", + d->dev.model_number ? d->dev.model_number : "", + d->dev.serial_number ? d->dev.serial_number : ""); + + if (ret < 0 || (size_t) ret >= buflen - len) { + return len; + } + + len += ret; + + return len; +} + + +int ICACHE_FLASH_ATTR wps_registrar_config_ap(struct wps_registrar* reg, + struct wps_credential* cred) +{ +#ifdef CONFIG_WPS2 + + if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | + WPS_ENCR_AES))) { + if (cred->encr_type & WPS_ENCR_WEP) { + wpa_printf(MSG_INFO, "WPS: Reject new AP settings " + "due to WEP configuration"); + return -1; + } + + wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to " + "invalid encr_type 0x%x", cred->encr_type); + return -1; + } + + if ((cred->encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == + WPS_ENCR_TKIP) { + wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> " + "TKIP+AES"); + cred->encr_type |= WPS_ENCR_AES; + } + + if ((cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == + WPS_AUTH_WPAPSK) { + wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> " + "WPAPSK+WPA2PSK"); + cred->auth_type |= WPS_AUTH_WPA2PSK; + } + +#endif /* CONFIG_WPS2 */ + + if (reg->wps->cred_cb) { + return reg->wps->cred_cb(reg->wps->cb_ctx, cred); + } + + return -1; +} + + +#ifdef CONFIG_WPS_NFC + +int ICACHE_FLASH_ATTR wps_registrar_add_nfc_pw_token(struct wps_registrar* reg, + const u8* pubkey_hash, u16 pw_id, + const u8* dev_pw, size_t dev_pw_len) +{ + struct wps_nfc_pw_token* token; + + if (dev_pw_len > WPS_OOB_DEVICE_PASSWORD_LEN) { + return -1; + } + + wps_free_nfc_pw_tokens(®->nfc_pw_tokens, pw_id); + + token = os_zalloc(sizeof(*token)); + + if (token == NULL) { + return -1; + } + + os_memcpy(token->pubkey_hash, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); + token->pw_id = pw_id; + os_memcpy(token->dev_pw, dev_pw, dev_pw_len); + token->dev_pw_len = dev_pw_len; + + dl_list_add(®->nfc_pw_tokens, &token->list); + + reg->selected_registrar = 1; + reg->pbc = 0; + wps_registrar_add_authorized_mac(reg, + (u8*) "\xff\xff\xff\xff\xff\xff"); + wps_registrar_selected_registrar_changed(reg); + eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); + eloop_register_timeout(WPS_PBC_WALK_TIME, 0, + wps_registrar_set_selected_timeout, + reg, NULL); + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_registrar_add_nfc_password_token(struct wps_registrar* reg, + const u8* oob_dev_pw, + size_t oob_dev_pw_len) +{ + const u8* pos, *hash, *dev_pw; + u16 id; + size_t dev_pw_len; + + if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 + + WPS_OOB_DEVICE_PASSWORD_MIN_LEN || + oob_dev_pw_len > WPS_OOB_PUBKEY_HASH_LEN + 2 + + WPS_OOB_DEVICE_PASSWORD_LEN) { + return -1; + } + + hash = oob_dev_pw; + pos = oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN; + id = WPA_GET_BE16(pos); + dev_pw = pos + 2; + dev_pw_len = oob_dev_pw + oob_dev_pw_len - dev_pw; + + wpa_printf(MSG_DEBUG, "WPS: Add NFC Password Token for Password ID %u", + id); + + wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash", + hash, WPS_OOB_PUBKEY_HASH_LEN); + wpa_hexdump_key(MSG_DEBUG, "WPS: Device Password", dev_pw, dev_pw_len); + + return wps_registrar_add_nfc_pw_token(reg, hash, id, dev_pw, + dev_pw_len); +} + + +void ICACHE_FLASH_ATTR wps_registrar_remove_nfc_pw_token(struct wps_registrar* reg, + struct wps_nfc_pw_token* token) +{ + wps_registrar_remove_authorized_mac(reg, + (u8*) "\xff\xff\xff\xff\xff\xff"); + wps_registrar_selected_registrar_changed(reg); +} + +#endif /* CONFIG_WPS_NFC */ diff --git a/components/wpa_supplicant/src/wps/wps_validate.c b/components/wpa_supplicant/src/wps/wps_validate.c new file mode 100644 index 00000000..cf9f4011 --- /dev/null +++ b/components/wpa_supplicant/src/wps/wps_validate.c @@ -0,0 +1,2689 @@ +/* + * Wi-Fi Protected Setup - Strict protocol validation routines + * Copyright (c) 2010, Atheros Communications, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "rom/ets_sys.h" + +#include "wpa/includes.h" +#include "wpa/common.h" +#include "wps/wps_i.h" +#include "wps/wps.h" + + +#ifndef WPS_STRICT_ALL +#define WPS_STRICT_WPS2 +#endif /* WPS_STRICT_ALL */ + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +static int ICACHE_FLASH_ATTR wps_validate_version(const u8* version, int mandatory) +{ + if (version == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Version attribute " + "missing"); + return -1; + } + + return 0; + } + + if (*version != 0x10) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Version attribute " + "value 0x%x", *version); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_version2(const u8* version2, int mandatory) +{ + if (version2 == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Version2 attribute " + "missing"); + return -1; + } + + return 0; + } + + if (*version2 < 0x20) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Version2 attribute " + "value 0x%x", *version2); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_request_type(const u8* request_type, int mandatory) +{ + if (request_type == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Request Type " + "attribute missing"); + return -1; + } + + return 0; + } + + if (*request_type > 0x03) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Request Type " + "attribute value 0x%x", *request_type); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_response_type(const u8* response_type, int mandatory) +{ + if (response_type == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Response Type " + "attribute missing"); + return -1; + } + + return 0; + } + + if (*response_type > 0x03) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Response Type " + "attribute value 0x%x", *response_type); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR valid_config_methods(u16 val, int wps2) +{ + if (wps2) { + if ((val & 0x6000) && !(val & WPS_CONFIG_DISPLAY)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Physical/Virtual " + "Display flag without old Display flag " + "set"); + return 0; + } + + if (!(val & 0x6000) && (val & WPS_CONFIG_DISPLAY)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Display flag " + "without Physical/Virtual Display flag"); + return 0; + } + + if ((val & 0x0600) && !(val & WPS_CONFIG_PUSHBUTTON)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Physical/Virtual " + "PushButton flag without old PushButton " + "flag set"); + return 0; + } + + if (!(val & 0x0600) && (val & WPS_CONFIG_PUSHBUTTON)) { + wpa_printf(MSG_INFO, "WPS-STRICT: PushButton flag " + "without Physical/Virtual PushButton flag"); + return 0; + } + } + + return 1; +} + + +static int ICACHE_FLASH_ATTR wps_validate_config_methods(const u8* config_methods, int wps2, + int mandatory) +{ + u16 val; + + if (config_methods == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Configuration " + "Methods attribute missing"); + return -1; + } + + return 0; + } + + val = WPA_GET_BE16(config_methods); + + if (!valid_config_methods(val, wps2)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration " + "Methods attribute value 0x%04x", val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_ap_config_methods(const u8* config_methods, int wps2, + int mandatory) +{ + u16 val; + + if (wps_validate_config_methods(config_methods, wps2, mandatory) < 0) { + return -1; + } + + if (config_methods == NULL) { + return 0; + } + + val = WPA_GET_BE16(config_methods); + + if (val & WPS_CONFIG_PUSHBUTTON) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration " + "Methods attribute value 0x%04x in AP info " + "(PushButton not allowed for registering new ER)", + val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_uuid_e(const u8* uuid_e, int mandatory) +{ + if (uuid_e == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: UUID-E " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_uuid_r(const u8* uuid_r, int mandatory) +{ + if (uuid_r == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: UUID-R " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_primary_dev_type(const u8* primary_dev_type, + int mandatory) +{ + if (primary_dev_type == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Primary Device Type " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_rf_bands(const u8* rf_bands, int mandatory) +{ + if (rf_bands == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: RF Bands " + "attribute missing"); + return -1; + } + + return 0; + } + + if (*rf_bands != WPS_RF_24GHZ && *rf_bands != WPS_RF_50GHZ && + *rf_bands != (WPS_RF_24GHZ | WPS_RF_50GHZ)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Rf Bands " + "attribute value 0x%x", *rf_bands); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_assoc_state(const u8* assoc_state, int mandatory) +{ + u16 val; + + if (assoc_state == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Association State " + "attribute missing"); + return -1; + } + + return 0; + } + + val = WPA_GET_BE16(assoc_state); + + if (val > 4) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Association State " + "attribute value 0x%04x", val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_config_error(const u8* config_error, int mandatory) +{ + u16 val; + + if (config_error == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Configuration Error " + "attribute missing"); + return -1; + } + + return 0; + } + + val = WPA_GET_BE16(config_error); + + if (val > 18) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration Error " + "attribute value 0x%04x", val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_dev_password_id(const u8* dev_password_id, + int mandatory) +{ + u16 val; + + if (dev_password_id == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Device Password ID " + "attribute missing"); + return -1; + } + + return 0; + } + + val = WPA_GET_BE16(dev_password_id); + + if (val >= 0x0006 && val <= 0x000f) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Device Password ID " + "attribute value 0x%04x", val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_manufacturer(const u8* manufacturer, size_t len, + int mandatory) +{ + if (manufacturer == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Manufacturer " + "attribute missing"); + return -1; + } + + return 0; + } + + if (len > 0 && manufacturer[len - 1] == 0) { + wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Manufacturer " + "attribute value", manufacturer, len); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_model_name(const u8* model_name, size_t len, + int mandatory) +{ + if (model_name == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Model Name " + "attribute missing"); + return -1; + } + + return 0; + } + + if (len > 0 && model_name[len - 1] == 0) { + wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Model Name " + "attribute value", model_name, len); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_model_number(const u8* model_number, size_t len, + int mandatory) +{ + if (model_number == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Model Number " + "attribute missing"); + return -1; + } + + return 0; + } + + if (len > 0 && model_number[len - 1] == 0) { + wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Model Number " + "attribute value", model_number, len); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_serial_number(const u8* serial_number, size_t len, + int mandatory) +{ + if (serial_number == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Serial Number " + "attribute missing"); + return -1; + } + + return 0; + } + + if (len > 0 && serial_number[len - 1] == 0) { + wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Serial " + "Number attribute value", + serial_number, len); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_dev_name(const u8* dev_name, size_t len, + int mandatory) +{ + if (dev_name == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Device Name " + "attribute missing"); + return -1; + } + + return 0; + } + + if (len > 0 && dev_name[len - 1] == 0) { + wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Device Name " + "attribute value", dev_name, len); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_request_to_enroll(const u8* request_to_enroll, + int mandatory) +{ + if (request_to_enroll == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Request to Enroll " + "attribute missing"); + return -1; + } + + return 0; + } + + if (*request_to_enroll > 0x01) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Request to Enroll " + "attribute value 0x%x", *request_to_enroll); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_req_dev_type(const u8* req_dev_type[], size_t num, + int mandatory) +{ + if (num == 0) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Requested Device " + "Type attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_wps_state(const u8* wps_state, int mandatory) +{ + if (wps_state == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Wi-Fi Protected " + "Setup State attribute missing"); + return -1; + } + + return 0; + } + + if (*wps_state != WPS_STATE_NOT_CONFIGURED && + *wps_state != WPS_STATE_CONFIGURED) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Wi-Fi Protected " + "Setup State attribute value 0x%x", *wps_state); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_ap_setup_locked(const u8* ap_setup_locked, + int mandatory) +{ + if (ap_setup_locked == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: AP Setup Locked " + "attribute missing"); + return -1; + } + + return 0; + } + + if (*ap_setup_locked > 1) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid AP Setup Locked " + "attribute value 0x%x", *ap_setup_locked); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_selected_registrar(const u8* selected_registrar, + int mandatory) +{ + if (selected_registrar == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Selected Registrar " + "attribute missing"); + return -1; + } + + return 0; + } + + if (*selected_registrar > 1) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Selected Registrar " + "attribute value 0x%x", *selected_registrar); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_sel_reg_config_methods(const u8* config_methods, + int wps2, int mandatory) +{ + u16 val; + + if (config_methods == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Selected Registrar " + "Configuration Methods attribute missing"); + return -1; + } + + return 0; + } + + val = WPA_GET_BE16(config_methods); + + if (!valid_config_methods(val, wps2)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Selected Registrar " + "Configuration Methods attribute value 0x%04x", + val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_authorized_macs(const u8* authorized_macs, size_t len, + int mandatory) +{ + if (authorized_macs == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Authorized MACs " + "attribute missing"); + return -1; + } + + return 0; + } + + if (len > 30 && (len % ETH_ALEN) != 0) { + wpa_hexdump(MSG_INFO, "WPS-STRICT: Invalid Authorized " + "MACs attribute value", authorized_macs, len); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_msg_type(const u8* msg_type, int mandatory) +{ + if (msg_type == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Message Type " + "attribute missing"); + return -1; + } + + return 0; + } + + if (*msg_type < WPS_Beacon || *msg_type > WPS_WSC_DONE) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Message Type " + "attribute value 0x%x", *msg_type); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_mac_addr(const u8* mac_addr, int mandatory) +{ + if (mac_addr == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: MAC Address " + "attribute missing"); + return -1; + } + + return 0; + } + + if (mac_addr[0] & 0x01) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid MAC Address " + "attribute value " MACSTR, MAC2STR(mac_addr)); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_enrollee_nonce(const u8* enrollee_nonce, int mandatory) +{ + if (enrollee_nonce == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Enrollee Nonce " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_registrar_nonce(const u8* registrar_nonce, + int mandatory) +{ + if (registrar_nonce == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Registrar Nonce " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_public_key(const u8* public_key, size_t len, + int mandatory) +{ + if (public_key == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Public Key " + "attribute missing"); + return -1; + } + + return 0; + } + + if (len != 192) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Public Key " + "attribute length %d", (int) len); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR num_bits_set(u16 val) +{ + int c; + + for (c = 0; val; c++) { + val &= val - 1; + } + + return c; +} + + +static int ICACHE_FLASH_ATTR wps_validate_auth_type_flags(const u8* flags, int mandatory) +{ + u16 val; + + if (flags == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Authentication Type " + "Flags attribute missing"); + return -1; + } + + return 0; + } + + val = WPA_GET_BE16(flags); + + if ((val & ~WPS_AUTH_TYPES) || !(val & WPS_AUTH_WPA2PSK)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Authentication Type " + "Flags attribute value 0x%04x", val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_auth_type(const u8* type, int mandatory) +{ + u16 val; + + if (type == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Authentication Type " + "attribute missing"); + return -1; + } + + return 0; + } + + val = WPA_GET_BE16(type); + + if ((val & ~WPS_AUTH_TYPES) || val == 0 || + (num_bits_set(val) > 1 && + val != (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK))) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Authentication Type " + "attribute value 0x%04x", val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_encr_type_flags(const u8* flags, int mandatory) +{ + u16 val; + + if (flags == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Encryption Type " + "Flags attribute missing"); + return -1; + } + + return 0; + } + + val = WPA_GET_BE16(flags); + + if ((val & ~WPS_ENCR_TYPES) || !(val & WPS_ENCR_AES)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encryption Type " + "Flags attribute value 0x%04x", val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_encr_type(const u8* type, int mandatory) +{ + u16 val; + + if (type == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Encryption Type " + "attribute missing"); + return -1; + } + + return 0; + } + + val = WPA_GET_BE16(type); + + if ((val & ~WPS_ENCR_TYPES) || val == 0 || + (num_bits_set(val) > 1 && val != (WPS_ENCR_TKIP | WPS_ENCR_AES))) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encryption Type " + "attribute value 0x%04x", val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_conn_type_flags(const u8* flags, int mandatory) +{ + if (flags == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Connection Type " + "Flags attribute missing"); + return -1; + } + + return 0; + } + + if ((*flags & ~(WPS_CONN_ESS | WPS_CONN_IBSS)) || + !(*flags & WPS_CONN_ESS)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Connection Type " + "Flags attribute value 0x%02x", *flags); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_os_version(const u8* os_version, int mandatory) +{ + if (os_version == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: OS Version " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_authenticator(const u8* authenticator, int mandatory) +{ + if (authenticator == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Authenticator " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR ICACHE_FLASH_ATTR wps_validate_e_hash1(const u8* hash, int mandatory) +{ + if (hash == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: E-Hash1 " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_e_hash2(const u8* hash, int mandatory) +{ + if (hash == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: E-Hash2 " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_r_hash1(const u8* hash, int mandatory) +{ + if (hash == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: R-Hash1 " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_r_hash2(const u8* hash, int mandatory) +{ + if (hash == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: R-Hash2 " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_encr_settings(const u8* encr_settings, size_t len, + int mandatory) +{ + if (encr_settings == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Encrypted Settings " + "attribute missing"); + return -1; + } + + return 0; + } + + if (len < 16) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encrypted Settings " + "attribute length %d", (int) len); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_settings_delay_time(const u8* delay, int mandatory) +{ + if (delay == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Settings Delay Time " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_r_snonce1(const u8* nonce, int mandatory) +{ + if (nonce == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: R-SNonce1 " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_r_snonce2(const u8* nonce, int mandatory) +{ + if (nonce == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: R-SNonce2 " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_e_snonce1(const u8* nonce, int mandatory) +{ + if (nonce == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: E-SNonce1 " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_e_snonce2(const u8* nonce, int mandatory) +{ + if (nonce == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: E-SNonce2 " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_key_wrap_auth(const u8* auth, int mandatory) +{ + if (auth == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Key Wrap " + "Authenticator attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_ssid(const u8* ssid, size_t ssid_len, int mandatory) +{ + if (ssid == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: SSID " + "attribute missing"); + return -1; + } + + return 0; + } + + if (ssid_len == 0 || ssid[ssid_len - 1] == 0) { + wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid SSID " + "attribute value", ssid, ssid_len); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_network_key_index(const u8* idx, int mandatory) +{ + if (idx == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Network Key Index " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_network_idx(const u8* idx, int mandatory) +{ + if (idx == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Network Index " + "attribute missing"); + return -1; + } + + return 0; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_network_key(const u8* key, size_t key_len, + const u8* encr_type, int mandatory) +{ + if (key == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Network Key " + "attribute missing"); + return -1; + } + + return 0; + } + + if (((encr_type == NULL || WPA_GET_BE16(encr_type) != WPS_ENCR_WEP) && + key_len > 8 && key_len < 64 && key[key_len - 1] == 0) || + key_len > 64) { + wpa_hexdump_ascii_key(MSG_INFO, "WPS-STRICT: Invalid Network " + "Key attribute value", key, key_len); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_network_key_shareable(const u8* val, int mandatory) +{ + if (val == NULL) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Network Key " + "Shareable attribute missing"); + return -1; + } + + return 0; + } + + if (*val > 1) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Network Key " + "Shareable attribute value 0x%x", *val); + return -1; + } + + return 0; +} + + +static int ICACHE_FLASH_ATTR wps_validate_cred(const u8* cred, size_t len) +{ + struct wps_parse_attr* attr; + struct wpabuf buf; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (cred == NULL) { + ret = -1; + goto _out; + } + + wpabuf_set(&buf, cred, len); + + if (wps_parse_msg(&buf, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse Credential"); + ret = -1; + goto _out; + } + + if (wps_validate_network_idx(attr->network_idx, 1) || + wps_validate_ssid(attr->ssid, attr->ssid_len, 1) || + wps_validate_auth_type(attr->auth_type, 1) || + wps_validate_encr_type(attr->encr_type, 1) || + wps_validate_network_key_index(attr->network_key_idx, 0) || + wps_validate_network_key(attr->network_key, attr->network_key_len, + attr->encr_type, 1) || + wps_validate_mac_addr(attr->mac_addr, 1) || + wps_validate_network_key_shareable(attr->network_key_shareable, 0)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Credential"); + ret = -1; + goto _out; + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +static int ICACHE_FLASH_ATTR wps_validate_credential(const u8* cred[], size_t len[], size_t num, + int mandatory) +{ + size_t i; + + if (num == 0) { + if (mandatory) { + wpa_printf(MSG_INFO, "WPS-STRICT: Credential " + "attribute missing"); + return -1; + } + + return 0; + } + + for (i = 0; i < num; i++) { + if (wps_validate_cred(cred[i], len[i]) < 0) { + return -1; + } + } + + return 0; +} + + +int ICACHE_FLASH_ATTR wps_validate_beacon(const struct wpabuf* wps_ie) +{ + struct wps_parse_attr* attr; + int wps2, sel_reg; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (wps_ie == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in Beacon frame"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(wps_ie, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in " + "Beacon frame"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + sel_reg = attr->selected_registrar != NULL && + *attr->selected_registrar != 0; + + if (wps_validate_version(attr->version, 1) || + wps_validate_wps_state(attr->wps_state, 1) || + wps_validate_ap_setup_locked(attr->ap_setup_locked, 0) || + wps_validate_selected_registrar(attr->selected_registrar, 0) || + wps_validate_dev_password_id(attr->dev_password_id, sel_reg) || + wps_validate_sel_reg_config_methods(attr->sel_reg_config_methods, + wps2, sel_reg) || + wps_validate_uuid_e(attr->uuid_e, 0) || + wps_validate_rf_bands(attr->rf_bands, 0) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_authorized_macs(attr->authorized_macs, + attr->authorized_macs_len, 0)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Beacon frame"); + ret = -1; + goto _out; + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_beacon_probe_resp(const struct wpabuf* wps_ie, int probe, + const u8* addr) +{ + struct wps_parse_attr* attr; + int wps2, sel_reg; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (wps_ie == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in " + "%sProbe Response frame", probe ? "" : "Beacon/"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(wps_ie, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in " + "%sProbe Response frame", probe ? "" : "Beacon/"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + sel_reg = attr->selected_registrar != NULL && + *attr->selected_registrar != 0; + + if (wps_validate_version(attr->version, 1) || + wps_validate_wps_state(attr->wps_state, 1) || + wps_validate_ap_setup_locked(attr->ap_setup_locked, 0) || + wps_validate_selected_registrar(attr->selected_registrar, 0) || + wps_validate_dev_password_id(attr->dev_password_id, sel_reg) || + wps_validate_sel_reg_config_methods(attr->sel_reg_config_methods, + wps2, sel_reg) || + wps_validate_response_type(attr->response_type, probe) || + wps_validate_uuid_e(attr->uuid_e, probe) || + wps_validate_manufacturer(attr->manufacturer, attr->manufacturer_len, + probe) || + wps_validate_model_name(attr->model_name, attr->model_name_len, + probe) || + wps_validate_model_number(attr->model_number, attr->model_number_len, + probe) || + wps_validate_serial_number(attr->serial_number, + attr->serial_number_len, probe) || + wps_validate_primary_dev_type(attr->primary_dev_type, probe) || + wps_validate_dev_name(attr->dev_name, attr->dev_name_len, probe) || + wps_validate_ap_config_methods(attr->config_methods, wps2, probe) || + wps_validate_rf_bands(attr->rf_bands, 0) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_authorized_macs(attr->authorized_macs, + attr->authorized_macs_len, 0)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid %sProbe Response " + "frame from " MACSTR, probe ? "" : "Beacon/", + MAC2STR(addr)); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_probe_req(const struct wpabuf* wps_ie, const u8* addr) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (wps_ie == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in " + "Probe Request frame"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(wps_ie, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in " + "Probe Request frame"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_request_type(attr->request_type, 1) || + wps_validate_config_methods(attr->config_methods, wps2, 1) || + wps_validate_uuid_e(attr->uuid_e, attr->uuid_r == NULL) || + wps_validate_uuid_r(attr->uuid_r, attr->uuid_e == NULL) || + wps_validate_primary_dev_type(attr->primary_dev_type, 1) || + wps_validate_rf_bands(attr->rf_bands, 1) || + wps_validate_assoc_state(attr->assoc_state, 1) || + wps_validate_config_error(attr->config_error, 1) || + wps_validate_dev_password_id(attr->dev_password_id, 1) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_manufacturer(attr->manufacturer, attr->manufacturer_len, + wps2) || + wps_validate_model_name(attr->model_name, attr->model_name_len, + wps2) || + wps_validate_model_number(attr->model_number, attr->model_number_len, + wps2) || + wps_validate_dev_name(attr->dev_name, attr->dev_name_len, wps2) || + wps_validate_request_to_enroll(attr->request_to_enroll, 0) || + wps_validate_req_dev_type(attr->req_dev_type, attr->num_req_dev_type, + 0)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Probe Request " + "frame from " MACSTR, MAC2STR(addr)); + ret = -1; + goto _out; + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_assoc_req(const struct wpabuf* wps_ie) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (wps_ie == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in " + "(Re)Association Request frame"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(wps_ie, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in " + "(Re)Association Request frame"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_request_type(attr->request_type, 1) || + wps_validate_version2(attr->version2, wps2)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid (Re)Association " + "Request frame"); + ret = -1; + goto _out; + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_assoc_resp(const struct wpabuf* wps_ie) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + + if (wps_ie == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in " + "(Re)Association Response frame"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(wps_ie, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in " + "(Re)Association Response frame"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_response_type(attr->response_type, 1) || + wps_validate_version2(attr->version2, wps2)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid (Re)Association " + "Response frame"); + ret = -1; + goto _out; + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m1(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M1"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M1"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_uuid_e(attr->uuid_e, 1) || + wps_validate_mac_addr(attr->mac_addr, 1) || + wps_validate_enrollee_nonce(attr->enrollee_nonce, 1) || + wps_validate_public_key(attr->public_key, attr->public_key_len, 1) || + wps_validate_auth_type_flags(attr->auth_type_flags, 1) || + wps_validate_encr_type_flags(attr->encr_type_flags, 1) || + wps_validate_conn_type_flags(attr->conn_type_flags, 1) || + wps_validate_config_methods(attr->config_methods, wps2, 1) || + wps_validate_wps_state(attr->wps_state, 1) || + wps_validate_manufacturer(attr->manufacturer, attr->manufacturer_len, + 1) || + wps_validate_model_name(attr->model_name, attr->model_name_len, 1) || + wps_validate_model_number(attr->model_number, attr->model_number_len, + 1) || + wps_validate_serial_number(attr->serial_number, + attr->serial_number_len, 1) || + wps_validate_primary_dev_type(attr->primary_dev_type, 1) || + wps_validate_dev_name(attr->dev_name, attr->dev_name_len, 1) || + wps_validate_rf_bands(attr->rf_bands, 1) || + wps_validate_assoc_state(attr->assoc_state, 1) || + wps_validate_dev_password_id(attr->dev_password_id, 1) || + wps_validate_config_error(attr->config_error, 1) || + wps_validate_os_version(attr->os_version, 1) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_request_to_enroll(attr->request_to_enroll, 0)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M1"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m2(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M2"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M2"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_enrollee_nonce(attr->enrollee_nonce, 1) || + wps_validate_registrar_nonce(attr->registrar_nonce, 1) || + wps_validate_uuid_r(attr->uuid_r, 1) || + wps_validate_public_key(attr->public_key, attr->public_key_len, 1) || + wps_validate_auth_type_flags(attr->auth_type_flags, 1) || + wps_validate_encr_type_flags(attr->encr_type_flags, 1) || + wps_validate_conn_type_flags(attr->conn_type_flags, 1) || + wps_validate_config_methods(attr->config_methods, wps2, 1) || + wps_validate_manufacturer(attr->manufacturer, attr->manufacturer_len, + 1) || + wps_validate_model_name(attr->model_name, attr->model_name_len, 1) || + wps_validate_model_number(attr->model_number, attr->model_number_len, + 1) || + wps_validate_serial_number(attr->serial_number, + attr->serial_number_len, 1) || + wps_validate_primary_dev_type(attr->primary_dev_type, 1) || + wps_validate_dev_name(attr->dev_name, attr->dev_name_len, 1) || + wps_validate_rf_bands(attr->rf_bands, 1) || + wps_validate_assoc_state(attr->assoc_state, 1) || + wps_validate_config_error(attr->config_error, 1) || + wps_validate_dev_password_id(attr->dev_password_id, 1) || + wps_validate_os_version(attr->os_version, 1) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_authenticator(attr->authenticator, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M2"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m2d(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M2D"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M2D"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_enrollee_nonce(attr->enrollee_nonce, 1) || + wps_validate_registrar_nonce(attr->registrar_nonce, 1) || + wps_validate_uuid_r(attr->uuid_r, 1) || + wps_validate_auth_type_flags(attr->auth_type_flags, 1) || + wps_validate_encr_type_flags(attr->encr_type_flags, 1) || + wps_validate_conn_type_flags(attr->conn_type_flags, 1) || + wps_validate_config_methods(attr->config_methods, wps2, 1) || + wps_validate_manufacturer(attr->manufacturer, attr->manufacturer_len, + 1) || + wps_validate_model_name(attr->model_name, attr->model_name_len, 1) || + wps_validate_model_number(attr->model_number, attr->model_number_len, + 1) || + wps_validate_serial_number(attr->serial_number, + attr->serial_number_len, 1) || + wps_validate_primary_dev_type(attr->primary_dev_type, 1) || + wps_validate_dev_name(attr->dev_name, attr->dev_name_len, 1) || + wps_validate_rf_bands(attr->rf_bands, 1) || + wps_validate_assoc_state(attr->assoc_state, 1) || + wps_validate_config_error(attr->config_error, 1) || + wps_validate_os_version(attr->os_version, 1) || + wps_validate_version2(attr->version2, wps2)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M2D"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m3(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M3"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M3"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_registrar_nonce(attr->registrar_nonce, 1) || + wps_validate_e_hash1(attr->e_hash1, 1) || + wps_validate_e_hash2(attr->e_hash2, 1) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_authenticator(attr->authenticator, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M3"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m4(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M4"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M4"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_enrollee_nonce(attr->enrollee_nonce, 1) || + wps_validate_r_hash1(attr->r_hash1, 1) || + wps_validate_r_hash2(attr->r_hash2, 1) || + wps_validate_encr_settings(attr->encr_settings, + attr->encr_settings_len, 1) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_authenticator(attr->authenticator, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M4"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m4_encr(const struct wpabuf* tlvs, int wps2) +{ + struct wps_parse_attr* attr; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M4 encrypted " + "settings"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M4 encrypted settings"); + ret = -1; + goto _out; + } + + if (wps_validate_r_snonce1(attr->r_snonce1, 1) || + wps_validate_key_wrap_auth(attr->key_wrap_auth, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M4 encrypted " + "settings"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m5(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M5"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M5"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_registrar_nonce(attr->registrar_nonce, 1) || + wps_validate_encr_settings(attr->encr_settings, + attr->encr_settings_len, 1) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_authenticator(attr->authenticator, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M5"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m5_encr(const struct wpabuf* tlvs, int wps2) +{ + struct wps_parse_attr* attr; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M5 encrypted " + "settings"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M5 encrypted settings"); + ret = -1; + goto _out; + } + + if (wps_validate_e_snonce1(attr->e_snonce1, 1) || + wps_validate_key_wrap_auth(attr->key_wrap_auth, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M5 encrypted " + "settings"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m6(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M6"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M6"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_enrollee_nonce(attr->enrollee_nonce, 1) || + wps_validate_encr_settings(attr->encr_settings, + attr->encr_settings_len, 1) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_authenticator(attr->authenticator, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M6"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m6_encr(const struct wpabuf* tlvs, int wps2) +{ + struct wps_parse_attr* attr; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M6 encrypted " + "settings"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M6 encrypted settings"); + ret = -1; + goto _out; + } + + if (wps_validate_r_snonce2(attr->r_snonce2, 1) || + wps_validate_key_wrap_auth(attr->key_wrap_auth, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M6 encrypted " + "settings"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m7(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M7"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M7"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_registrar_nonce(attr->registrar_nonce, 1) || + wps_validate_encr_settings(attr->encr_settings, + attr->encr_settings_len, 1) || + wps_validate_settings_delay_time(attr->settings_delay_time, 0) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_authenticator(attr->authenticator, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M7"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m7_encr(const struct wpabuf* tlvs, int ap, int wps2) +{ + struct wps_parse_attr* attr; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M7 encrypted " + "settings"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M7 encrypted settings"); + ret = -1; + goto _out; + } + + if (wps_validate_e_snonce2(attr->e_snonce2, 1) || + wps_validate_ssid(attr->ssid, attr->ssid_len, !ap) || + wps_validate_mac_addr(attr->mac_addr, !ap) || + wps_validate_auth_type(attr->auth_type, !ap) || + wps_validate_encr_type(attr->encr_type, !ap) || + wps_validate_network_key_index(attr->network_key_idx, 0) || + wps_validate_network_key(attr->network_key, attr->network_key_len, + attr->encr_type, !ap) || + wps_validate_key_wrap_auth(attr->key_wrap_auth, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M7 encrypted " + "settings"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m8(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M8"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M8"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_enrollee_nonce(attr->enrollee_nonce, 1) || + wps_validate_encr_settings(attr->encr_settings, + attr->encr_settings_len, 1) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_authenticator(attr->authenticator, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M8"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_m8_encr(const struct wpabuf* tlvs, int ap, int wps2) +{ + struct wps_parse_attr* attr; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M8 encrypted " + "settings"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in M8 encrypted settings"); + ret = -1; + goto _out; + } + + if (wps_validate_ssid(attr->ssid, attr->ssid_len, ap) || + wps_validate_auth_type(attr->auth_type, ap) || + wps_validate_encr_type(attr->encr_type, ap) || + wps_validate_network_key_index(attr->network_key_idx, 0) || + wps_validate_mac_addr(attr->mac_addr, ap) || + wps_validate_credential(attr->cred, attr->cred_len, attr->num_cred, + !ap) || + wps_validate_key_wrap_auth(attr->key_wrap_auth, 1)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M8 encrypted " + "settings"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_wsc_ack(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_ACK"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in WSC_ACK"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_enrollee_nonce(attr->enrollee_nonce, 1) || + wps_validate_registrar_nonce(attr->registrar_nonce, 1) || + wps_validate_version2(attr->version2, wps2)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_ACK"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_wsc_nack(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_NACK"); + ret = -1; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in WSC_NACK"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_enrollee_nonce(attr->enrollee_nonce, 1) || + wps_validate_registrar_nonce(attr->registrar_nonce, 1) || + wps_validate_config_error(attr->config_error, 1) || + wps_validate_version2(attr->version2, wps2)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_NACK"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + goto _out; + ret = -1; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_wsc_done(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_Done"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in WSC_Done"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + + if (wps_validate_version(attr->version, 1) || + wps_validate_msg_type(attr->msg_type, 1) || + wps_validate_enrollee_nonce(attr->enrollee_nonce, 1) || + wps_validate_registrar_nonce(attr->registrar_nonce, 1) || + wps_validate_version2(attr->version2, wps2)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_Done"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret = -1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +} + + +int ICACHE_FLASH_ATTR wps_validate_upnp_set_selected_registrar(const struct wpabuf* tlvs) +{ + struct wps_parse_attr* attr; + int wps2; + int sel_reg; + int ret; + + attr = (struct wps_parse_attr*)os_zalloc(sizeof(struct wps_parse_attr)); + + if (attr == NULL) { + ret = -99; + goto _out; + } + + if (tlvs == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in " + "SetSelectedRegistrar"); + ret = -1; + goto _out; + } + + if (wps_parse_msg(tlvs, attr) < 0) { + wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes " + "in SetSelectedRegistrar"); + ret = -1; + goto _out; + } + + wps2 = attr->version2 != NULL; + sel_reg = attr->selected_registrar != NULL && + *attr->selected_registrar != 0; + + if (wps_validate_version(attr->version, 1) || + wps_validate_dev_password_id(attr->dev_password_id, sel_reg) || + wps_validate_sel_reg_config_methods(attr->sel_reg_config_methods, + wps2, sel_reg) || + wps_validate_version2(attr->version2, wps2) || + wps_validate_authorized_macs(attr->authorized_macs, + attr->authorized_macs_len, wps2) || + wps_validate_uuid_r(attr->uuid_r, wps2)) { + wpa_printf(MSG_INFO, "WPS-STRICT: Invalid " + "SetSelectedRegistrar"); +#ifdef WPS_STRICT_WPS2 + + if (wps2) { + ret = -1; + goto _out; + } + +#else /* WPS_STRICT_WPS2 */ + ret - 1; + goto _out; +#endif /* WPS_STRICT_WPS2 */ + } + + ret = 0; +_out: + + if (attr) { + os_free(attr); + } + + return ret; +}