diff options
Diffstat (limited to 'freebsd/contrib/wpa/src')
99 files changed, 5103 insertions, 997 deletions
diff --git a/freebsd/contrib/wpa/src/ap/ap_config.h b/freebsd/contrib/wpa/src/ap/ap_config.h index de470a96..8c8f7e28 100644 --- a/freebsd/contrib/wpa/src/ap/ap_config.h +++ b/freebsd/contrib/wpa/src/ap/ap_config.h @@ -10,12 +10,14 @@ #define HOSTAPD_CONFIG_H #include "common/defs.h" +#include "utils/list.h" #include "ip_addr.h" #include "common/wpa_common.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "wps/wps.h" #include "fst/fst.h" +#include "vlan.h" /** * mesh_conf - local MBSS state and settings @@ -39,6 +41,10 @@ struct mesh_conf { #define MESH_CONF_SEC_AUTH BIT(1) #define MESH_CONF_SEC_AMPE BIT(2) unsigned int security; + enum mfp_options ieee80211w; + unsigned int pairwise_cipher; + unsigned int group_cipher; + unsigned int mgmt_group_cipher; int dot11MeshMaxRetries; int dot11MeshRetryTimeout; /* msec */ int dot11MeshConfirmTimeout; /* msec */ @@ -52,7 +58,7 @@ typedef u8 macaddr[ETH_ALEN]; struct mac_acl_entry { macaddr addr; - int vlan_id; + struct vlan_description vlan_id; }; struct hostapd_radius_servers; @@ -102,6 +108,7 @@ struct hostapd_ssid { #define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1 #define DYNAMIC_VLAN_NAMING_END 2 int vlan_naming; + int per_sta_vif; #ifdef CONFIG_FULL_DYNAMIC_VLAN char *vlan_tagged_interface; #endif /* CONFIG_FULL_DYNAMIC_VLAN */ @@ -113,6 +120,7 @@ struct hostapd_ssid { struct hostapd_vlan { struct hostapd_vlan *next; int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */ + struct vlan_description vlan_desc; char ifname[IFNAMSIZ + 1]; int configured; int dynamic_vlan; @@ -124,9 +132,14 @@ struct hostapd_vlan { }; #define PMK_LEN 32 +#define MIN_PASSPHRASE_LEN 8 +#define MAX_PASSPHRASE_LEN 63 struct hostapd_sta_wpa_psk_short { struct hostapd_sta_wpa_psk_short *next; + unsigned int is_passphrase:1; u8 psk[PMK_LEN]; + char passphrase[MAX_PASSPHRASE_LEN + 1]; + int ref; /* (number of references held) - 1 */ }; struct hostapd_wpa_psk { @@ -205,6 +218,13 @@ struct hostapd_nai_realm_data { } eap_method[MAX_NAI_EAP_METHODS]; }; +struct anqp_element { + struct dl_list list; + u16 infoid; + struct wpabuf *payload; +}; + + /** * struct hostapd_bss_config - Per-BSS configuration */ @@ -231,6 +251,7 @@ struct hostapd_bss_config { struct hostapd_eap_user *eap_user; char *eap_user_sqlite; char *eap_sim_db; + unsigned int eap_sim_db_timeout; int eap_server_erp; /* Whether ERP is enabled on internal EAP server */ struct hostapd_ip_addr own_ip_addr; char *nas_identifier; @@ -242,6 +263,7 @@ struct hostapd_bss_config { int radius_das_port; unsigned int radius_das_time_window; int radius_das_require_event_timestamp; + int radius_das_require_message_authenticator; struct hostapd_ip_addr radius_das_client_addr; u8 *radius_das_shared_secret; size_t radius_das_shared_secret_len; @@ -332,6 +354,7 @@ struct hostapd_bss_config { int check_crl; unsigned int tls_session_lifetime; char *ocsp_stapling_response; + char *ocsp_stapling_response_multi; char *dh_file; char *openssl_ciphers; u8 *pac_opaque_encr_key; @@ -358,6 +381,7 @@ struct hostapd_bss_config { int ap_max_inactivity; int ignore_broadcast_ssid; + int no_probe_resp_if_max_sta; int wmm_enabled; int wmm_uapsd; @@ -481,8 +505,11 @@ struct hostapd_bss_config { unsigned int nai_realm_count; struct hostapd_nai_realm_data *nai_realm_data; + struct dl_list anqp_elem; /* list of struct anqp_element */ + u16 gas_comeback_delay; int gas_frag_limit; + int gas_address3; u8 qos_map_set[16 + 2 * 21]; unsigned int qos_map_set_len; @@ -536,6 +563,7 @@ struct hostapd_bss_config { #endif /* CONFIG_RADIUS_TEST */ struct wpabuf *vendor_elements; + struct wpabuf *assocresp_elements; unsigned int sae_anti_clogging_threshold; int *sae_groups; @@ -551,12 +579,22 @@ struct hostapd_bss_config { #define MESH_ENABLED BIT(0) int mesh; - int radio_measurements; + u8 radio_measurements[RRM_CAPABILITIES_IE_LEN]; int vendor_vht; + int use_sta_nsts; char *no_probe_resp_if_seen_on; char *no_auth_if_seen_on; + + int pbss; + +#ifdef CONFIG_MBO + int mbo_enabled; +#endif /* CONFIG_MBO */ + + int ftm_responder; + int ftm_initiator; }; @@ -638,6 +676,9 @@ struct hostapd_config { u8 vht_oper_centr_freq_seg0_idx; u8 vht_oper_centr_freq_seg1_idx; + /* Use driver-generated interface addresses when adding multiple BSSs */ + u8 use_driver_iface_addr; + #ifdef CONFIG_FST struct fst_iface_cfg fst_cfg; #endif /* CONFIG_FST */ @@ -652,6 +693,7 @@ struct hostapd_config { double ignore_assoc_probability; double ignore_reassoc_probability; double corrupt_gtk_rekey_mic_probability; + int ecsa_ie_only; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_ACS @@ -662,11 +704,13 @@ struct hostapd_config { } *acs_chan_bias; unsigned int num_acs_chan_bias; #endif /* CONFIG_ACS */ + + struct wpabuf *lci; + struct wpabuf *civic; }; 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_eap_user(struct hostapd_eap_user *user); @@ -674,13 +718,14 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p); void hostapd_config_free_bss(struct hostapd_bss_config *conf); 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); + const u8 *addr, struct vlan_description *vlan_id); int hostapd_rate_found(int *list, int rate); const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, const u8 *addr, const u8 *p2p_dev_addr, const u8 *prev_psk); int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf); -int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id); +int hostapd_vlan_valid(struct hostapd_vlan *vlan, + struct vlan_description *vlan_desc); const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id); struct hostapd_radius_attr * diff --git a/freebsd/contrib/wpa/src/ap/ap_drv_ops.c b/freebsd/contrib/wpa/src/ap/ap_drv_ops.c index d20ee93f..c0111c37 100644 --- a/freebsd/contrib/wpa/src/ap/ap_drv_ops.c +++ b/freebsd/contrib/wpa/src/ap/ap_drv_ops.c @@ -35,10 +35,36 @@ u32 hostapd_sta_flags_to_drv(u32 flags) res |= WPA_STA_SHORT_PREAMBLE; if (flags & WLAN_STA_MFP) res |= WPA_STA_MFP; + if (flags & WLAN_STA_AUTH) + res |= WPA_STA_AUTHENTICATED; + if (flags & WLAN_STA_ASSOC) + res |= WPA_STA_ASSOCIATED; return res; } +static int add_buf(struct wpabuf **dst, const struct wpabuf *src) +{ + if (!src) + return 0; + if (wpabuf_resize(dst, wpabuf_len(src)) != 0) + return -1; + wpabuf_put_buf(*dst, src); + return 0; +} + + +static int add_buf_data(struct wpabuf **dst, const u8 *data, size_t len) +{ + if (!data || !len) + return 0; + if (wpabuf_resize(dst, len) != 0) + return -1; + wpabuf_put_data(*dst, data, len); + return 0; +} + + int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf **beacon_ret, struct wpabuf **proberesp_ret, @@ -51,82 +77,38 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, pos = buf; pos = hostapd_eid_time_adv(hapd, pos); - if (pos != buf) { - if (wpabuf_resize(&beacon, pos - buf) != 0) - goto fail; - wpabuf_put_data(beacon, buf, pos - buf); - } + if (add_buf_data(&beacon, buf, pos - buf) < 0) + goto fail; pos = hostapd_eid_time_zone(hapd, pos); - if (pos != buf) { - if (wpabuf_resize(&proberesp, pos - buf) != 0) - goto fail; - wpabuf_put_data(proberesp, buf, pos - buf); - } + if (add_buf_data(&proberesp, buf, pos - buf) < 0) + goto fail; pos = buf; pos = hostapd_eid_ext_capab(hapd, pos); - if (pos != buf) { - if (wpabuf_resize(&assocresp, pos - buf) != 0) - goto fail; - wpabuf_put_data(assocresp, buf, pos - buf); - } + if (add_buf_data(&assocresp, buf, pos - buf) < 0) + goto fail; pos = hostapd_eid_interworking(hapd, pos); pos = hostapd_eid_adv_proto(hapd, pos); pos = hostapd_eid_roaming_consortium(hapd, pos); - if (pos != buf) { - if (wpabuf_resize(&beacon, pos - buf) != 0) - goto fail; - wpabuf_put_data(beacon, buf, pos - buf); - - if (wpabuf_resize(&proberesp, pos - buf) != 0) - goto fail; - wpabuf_put_data(proberesp, buf, pos - buf); - } + if (add_buf_data(&beacon, buf, pos - buf) < 0 || + add_buf_data(&proberesp, buf, pos - buf) < 0) + goto fail; #ifdef CONFIG_FST - if (hapd->iface->fst_ies) { - size_t add = wpabuf_len(hapd->iface->fst_ies); - - if (wpabuf_resize(&beacon, add) < 0) - goto fail; - wpabuf_put_buf(beacon, hapd->iface->fst_ies); - if (wpabuf_resize(&proberesp, add) < 0) - goto fail; - wpabuf_put_buf(proberesp, hapd->iface->fst_ies); - if (wpabuf_resize(&assocresp, add) < 0) - goto fail; - wpabuf_put_buf(assocresp, hapd->iface->fst_ies); - } + if (add_buf(&beacon, hapd->iface->fst_ies) < 0 || + add_buf(&proberesp, hapd->iface->fst_ies) < 0 || + add_buf(&assocresp, hapd->iface->fst_ies) < 0) + goto fail; #endif /* CONFIG_FST */ - if (hapd->wps_beacon_ie) { - if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) < - 0) - goto fail; - wpabuf_put_buf(beacon, hapd->wps_beacon_ie); - } - - if (hapd->wps_probe_resp_ie) { - if (wpabuf_resize(&proberesp, - wpabuf_len(hapd->wps_probe_resp_ie)) < 0) - goto fail; - wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie); - } + if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 || + add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0) + goto fail; #ifdef CONFIG_P2P - if (hapd->p2p_beacon_ie) { - if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) < - 0) - goto fail; - wpabuf_put_buf(beacon, hapd->p2p_beacon_ie); - } - - if (hapd->p2p_probe_resp_ie) { - if (wpabuf_resize(&proberesp, - wpabuf_len(hapd->p2p_probe_resp_ie)) < 0) - goto fail; - wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie); - } + if (add_buf(&beacon, hapd->p2p_beacon_ie) < 0 || + add_buf(&proberesp, hapd->p2p_probe_resp_ie) < 0) + goto fail; #endif /* CONFIG_P2P */ #ifdef CONFIG_P2P_MANAGER @@ -150,8 +132,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, #ifdef CONFIG_WPS if (hapd->conf->wps_state) { struct wpabuf *a = wps_build_assoc_resp_ie(); - if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0) - wpabuf_put_buf(assocresp, a); + add_buf(&assocresp, a); wpabuf_free(a); } #endif /* CONFIG_WPS */ @@ -171,44 +152,36 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, if (hapd->p2p_group) { struct wpabuf *a; a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS); - if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0) - wpabuf_put_buf(assocresp, a); + add_buf(&assocresp, a); wpabuf_free(a); } #endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_HS20 - pos = buf; - pos = hostapd_eid_hs20_indication(hapd, pos); - if (pos != buf) { - if (wpabuf_resize(&beacon, pos - buf) != 0) - goto fail; - wpabuf_put_data(beacon, buf, pos - buf); - - if (wpabuf_resize(&proberesp, pos - buf) != 0) - goto fail; - wpabuf_put_data(proberesp, buf, pos - buf); - } + pos = hostapd_eid_hs20_indication(hapd, buf); + if (add_buf_data(&beacon, buf, pos - buf) < 0 || + add_buf_data(&proberesp, buf, pos - buf) < 0) + goto fail; pos = hostapd_eid_osen(hapd, buf); - if (pos != buf) { - if (wpabuf_resize(&beacon, pos - buf) != 0) - goto fail; - wpabuf_put_data(beacon, buf, pos - buf); + if (add_buf_data(&beacon, buf, pos - buf) < 0 || + add_buf_data(&proberesp, buf, pos - buf) < 0) + goto fail; +#endif /* CONFIG_HS20 */ - if (wpabuf_resize(&proberesp, pos - buf) != 0) +#ifdef CONFIG_MBO + if (hapd->conf->mbo_enabled) { + pos = hostapd_eid_mbo(hapd, buf, sizeof(buf)); + if (add_buf_data(&beacon, buf, pos - buf) < 0 || + add_buf_data(&proberesp, buf, pos - buf) < 0 || + add_buf_data(&assocresp, buf, pos - buf) < 0) goto fail; - wpabuf_put_data(proberesp, buf, pos - buf); } -#endif /* CONFIG_HS20 */ +#endif /* CONFIG_MBO */ - if (hapd->conf->vendor_elements) { - size_t add = wpabuf_len(hapd->conf->vendor_elements); - if (wpabuf_resize(&beacon, add) == 0) - wpabuf_put_buf(beacon, hapd->conf->vendor_elements); - if (wpabuf_resize(&proberesp, add) == 0) - wpabuf_put_buf(proberesp, hapd->conf->vendor_elements); - } + add_buf(&beacon, hapd->conf->vendor_elements); + add_buf(&proberesp, hapd->conf->vendor_elements); + add_buf(&assocresp, hapd->conf->assocresp_elements); *beacon_ret = beacon; *proberesp_ret = proberesp; @@ -392,7 +365,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, u16 listen_interval, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, - u32 flags, u8 qosinfo, u8 vht_opmode) + u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, + int set) { struct hostapd_sta_add_params params; @@ -414,6 +388,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, params.vht_opmode = vht_opmode; params.flags = hostapd_sta_flags_to_drv(flags); params.qosinfo = qosinfo; + params.support_p2p_ps = supp_p2p_ps; + params.set = set; return hapd->driver->sta_add(hapd->drv_priv, ¶ms); } @@ -470,7 +446,7 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type, return -1; return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr, bss_ctx, drv_priv, force_ifname, if_addr, - bridge, use_existing); + bridge, use_existing, 1); } @@ -649,16 +625,28 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd, int hostapd_drv_send_mlme(struct hostapd_data *hapd, const void *msg, size_t len, int noack) { + if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv) + return 0; + return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0, + NULL, 0); +} + + +int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd, + const void *msg, size_t len, int noack, + const u16 *csa_offs, size_t csa_offs_len) +{ if (hapd->driver == NULL || hapd->driver->send_mlme == NULL) return 0; - return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0); + return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0, + csa_offs, csa_offs_len); } int hostapd_drv_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason) { - if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL) + if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv) return 0; return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr, reason); @@ -668,7 +656,7 @@ int hostapd_drv_sta_deauth(struct hostapd_data *hapd, int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, const u8 *addr, int reason) { - if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL) + if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv) return 0; return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr, reason); @@ -689,6 +677,36 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq, unsigned int wait, const u8 *dst, const u8 *data, size_t len) { + const u8 *bssid; + const u8 wildcard_bssid[ETH_ALEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv) + return 0; + bssid = hapd->own_addr; + if (!is_multicast_ether_addr(dst) && + len > 0 && data[0] == WLAN_ACTION_PUBLIC) { + struct sta_info *sta; + + /* + * Public Action frames to a STA that is not a member of the BSS + * shall use wildcard BSSID value. + */ + sta = ap_get_sta(hapd, dst); + if (!sta || !(sta->flags & WLAN_STA_ASSOC)) + bssid = wildcard_bssid; + } + return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst, + hapd->own_addr, bssid, data, len, 0); +} + + +int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd, + unsigned int freq, + unsigned int wait, const u8 *dst, + const u8 *data, size_t len) +{ if (hapd->driver == NULL || hapd->driver->send_action == NULL) return 0; return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst, @@ -738,7 +756,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set, u8 qos_map_set_len) { - if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL) + if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv) return 0; return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set, qos_map_set_len); @@ -764,6 +782,20 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, } +void hostapd_get_ext_capa(struct hostapd_iface *iface) +{ + struct hostapd_data *hapd = iface->bss[0]; + + if (!hapd->driver || !hapd->driver->get_ext_capab) + return; + + hapd->driver->get_ext_capab(hapd->drv_priv, WPA_IF_AP_BSS, + &iface->extended_capa, + &iface->extended_capa_mask, + &iface->extended_capa_len); +} + + int hostapd_drv_do_acs(struct hostapd_data *hapd) { struct drv_acs_params params; diff --git a/freebsd/contrib/wpa/src/ap/ap_drv_ops.h b/freebsd/contrib/wpa/src/ap/ap_drv_ops.h index 82eaf3f0..0bb7954e 100644 --- a/freebsd/contrib/wpa/src/ap/ap_drv_ops.h +++ b/freebsd/contrib/wpa/src/ap/ap_drv_ops.h @@ -41,7 +41,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, u16 listen_interval, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, - u32 flags, u8 qosinfo, u8 vht_opmode); + u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, + int set); int hostapd_set_privacy(struct hostapd_data *hapd, int enabled); int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem, size_t elem_len); @@ -88,6 +89,9 @@ int hostapd_drv_set_key(const char *ifname, const u8 *key, size_t key_len); int hostapd_drv_send_mlme(struct hostapd_data *hapd, const void *msg, size_t len, int noack); +int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd, + const void *msg, size_t len, int noack, + const u16 *csa_offs, size_t csa_offs_len); int hostapd_drv_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason); int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, @@ -95,6 +99,10 @@ int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq, unsigned int wait, const u8 *dst, const u8 *data, size_t len); +int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd, + unsigned int freq, + unsigned int wait, const u8 *dst, + const u8 *data, size_t len); int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr, u16 auth_alg); int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr, @@ -120,6 +128,8 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd, int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set, u8 qos_map_set_len); +void hostapd_get_ext_capa(struct hostapd_iface *iface); + static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd, int enabled) { @@ -150,7 +160,7 @@ static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd, static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd, const u8 *addr) { - if (hapd->driver == NULL || hapd->driver->sta_remove == NULL) + if (!hapd->driver || !hapd->driver->sta_remove || !hapd->drv_priv) return 0; return hapd->driver->sta_remove(hapd->drv_priv, addr); } @@ -273,7 +283,7 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd, static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf, size_t buflen) { - if (hapd->driver == NULL || hapd->driver->status == NULL) + if (!hapd->driver || !hapd->driver->status || !hapd->drv_priv) return -1; return hapd->driver->status(hapd->drv_priv, buf, buflen); } @@ -332,7 +342,7 @@ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd, static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd) { - if (hapd->driver == NULL || hapd->driver->stop_ap == NULL) + if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv) return 0; return hapd->driver->stop_ap(hapd->drv_priv); } diff --git a/freebsd/contrib/wpa/src/ap/hostapd.h b/freebsd/contrib/wpa/src/ap/hostapd.h index dcf51f00..dec46f69 100644 --- a/freebsd/contrib/wpa/src/ap/hostapd.h +++ b/freebsd/contrib/wpa/src/ap/hostapd.h @@ -41,7 +41,7 @@ struct hapd_interfaces { size_t count; int global_ctrl_sock; - struct wpa_ctrl_dst *global_ctrl_dst; + struct dl_list global_ctrl_dst; char *global_iface_path; char *global_iface_name; #ifndef CONFIG_NATIVE_WINDOWS @@ -53,6 +53,7 @@ struct hapd_interfaces { #ifndef CONFIG_NO_VLAN struct dynamic_iface *vlan_priv; #endif /* CONFIG_NO_VLAN */ + int eloop_initialized; }; enum hostapd_chan_status { @@ -99,6 +100,16 @@ struct wps_stat { u8 peer_addr[ETH_ALEN]; }; +struct hostapd_neighbor_entry { + struct dl_list list; + u8 bssid[ETH_ALEN]; + struct wpa_ssid_value ssid; + struct wpabuf *nr; + struct wpabuf *lci; + struct wpabuf *civic; + /* LCI update time */ + struct os_time lci_date; +}; /** * struct hostapd_data - hostapd per-BSS data structure @@ -138,7 +149,7 @@ struct hostapd_data { 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; + u64 acct_session_id; struct radius_das_data *radius_das; struct iapp_data *iapp; @@ -155,7 +166,7 @@ struct hostapd_data { int tkip_countermeasures; int ctrl_sock; - struct wpa_ctrl_dst *ctrl_dst; + struct dl_list ctrl_dst; void *ssl_ctx; void *eap_sim_db_priv; @@ -228,6 +239,8 @@ struct hostapd_data { unsigned int cs_c_off_beacon; unsigned int cs_c_off_proberesp; int csa_in_progress; + unsigned int cs_c_off_ecsa_beacon; + unsigned int cs_c_off_ecsa_proberesp; /* BSS Load */ unsigned int bss_load_update_timeout; @@ -256,9 +269,11 @@ struct hostapd_data { #ifdef CONFIG_MESH int num_plinks; int max_plinks; - void (*mesh_sta_free_cb)(struct sta_info *sta); + void (*mesh_sta_free_cb)(struct hostapd_data *hapd, + struct sta_info *sta); struct wpabuf *mesh_pending_auth; struct os_reltime mesh_pending_auth_time; + u8 mesh_required_peer[ETH_ALEN]; #endif /* CONFIG_MESH */ #ifdef CONFIG_SQLITE @@ -278,6 +293,17 @@ struct hostapd_data { struct l2_packet_data *l2_test; #endif /* CONFIG_TESTING_OPTIONS */ + +#ifdef CONFIG_MBO + unsigned int mbo_assoc_disallow; +#endif /* CONFIG_MBO */ + + struct dl_list nr_db; + + u8 lci_req_token; + u8 range_req_token; + unsigned int lci_req_active:1; + unsigned int range_req_active:1; }; @@ -285,6 +311,9 @@ struct hostapd_sta_info { struct dl_list list; u8 addr[ETH_ALEN]; struct os_reltime last_seen; +#ifdef CONFIG_TAXONOMY + struct wpabuf *probe_ie_taxonomy; +#endif /* CONFIG_TAXONOMY */ }; /** @@ -327,6 +356,15 @@ struct hostapd_iface { */ unsigned int driver_ap_teardown:1; + /* + * When set, indicates that this interface is part of list of + * interfaces that need to be started together (synchronously). + */ + unsigned int need_to_start_in_sync:1; + + /* Ready to start but waiting for other interfaces to become ready. */ + unsigned int ready_to_start_in_sync:1; + 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]; @@ -402,6 +440,9 @@ struct hostapd_iface { u64 last_channel_time_busy; u8 channel_utilization; + /* eCSA IE will be added only if operating class is specified */ + u8 cs_oper_class; + unsigned int dfs_cac_ms; struct os_reltime dfs_cac_start; @@ -433,6 +474,7 @@ 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); +struct hostapd_iface * hostapd_alloc_iface(void); struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces, const char *config_file); struct hostapd_iface * @@ -449,6 +491,7 @@ int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf); void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator); void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s); const char * hostapd_state_text(enum hostapd_iface_state s); +int hostapd_csa_in_progress(struct hostapd_iface *iface); int hostapd_switch_channel(struct hostapd_data *hapd, struct csa_settings *settings); void @@ -478,6 +521,11 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, int ssi_signal); void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, int offset, int width, int cf1, int cf2); +struct survey_results; +void hostapd_event_get_survey(struct hostapd_iface *iface, + struct survey_results *survey_results); +void hostapd_acs_channel_selected(struct hostapd_data *hapd, + struct acs_selected_channels *acs_res); const struct hostapd_eap_user * hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, diff --git a/freebsd/contrib/wpa/src/ap/ieee802_11.h b/freebsd/contrib/wpa/src/ap/ieee802_11.h index 44c1bff3..0327dec2 100644 --- a/freebsd/contrib/wpa/src/ap/ieee802_11.h +++ b/freebsd/contrib/wpa/src/ap/ieee802_11.h @@ -49,9 +49,13 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid); -u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts); u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid); + int hostapd_ht_operation_update(struct hostapd_iface *iface); void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, const u8 *addr, const u8 *trans_id); @@ -61,6 +65,7 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd, void hostapd_get_vht_capab(struct hostapd_data *hapd, struct ieee80211_vht_capabilities *vht_cap, struct ieee80211_vht_capabilities *neg_vht_cap); +int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta); u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *ht_capab); u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta, @@ -97,6 +102,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta); #ifdef CONFIG_SAE void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta); +void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta); #else /* CONFIG_SAE */ static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta) @@ -104,4 +110,29 @@ static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd, } #endif /* CONFIG_SAE */ +#ifdef CONFIG_MBO + +u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len); + +u8 hostapd_mbo_ie_len(struct hostapd_data *hapd); + +#else /* CONFIG_MBO */ + +static inline u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, + size_t len) +{ + return eid; +} + +static inline u8 hostapd_mbo_ie_len(struct hostapd_data *hapd) +{ + return 0; +} + +#endif /* CONFIG_MBO */ + +void ap_copy_sta_supp_op_classes(struct sta_info *sta, + const u8 *supp_op_classes, + size_t supp_op_classes_len); + #endif /* IEEE802_11_H */ diff --git a/freebsd/contrib/wpa/src/ap/ieee802_11_auth.h b/freebsd/contrib/wpa/src/ap/ieee802_11_auth.h index b66f244b..71f53b96 100644 --- a/freebsd/contrib/wpa/src/ap/ieee802_11_auth.h +++ b/freebsd/contrib/wpa/src/ap/ieee802_11_auth.h @@ -16,9 +16,12 @@ enum { HOSTAPD_ACL_ACCEPT_TIMEOUT = 3 }; +int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr, + struct vlan_description *vlan_id); int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, const u8 *msg, size_t len, u32 *session_timeout, - u32 *acct_interim_interval, int *vlan_id, + u32 *acct_interim_interval, + struct vlan_description *vlan_id, struct hostapd_sta_wpa_psk_short **psk, char **identity, char **radius_cui); int hostapd_acl_init(struct hostapd_data *hapd); diff --git a/freebsd/contrib/wpa/src/ap/ieee802_11_shared.c b/freebsd/contrib/wpa/src/ap/ieee802_11_shared.c index ec6deaf5..8a08e93d 100644 --- a/freebsd/contrib/wpa/src/ap/ieee802_11_shared.c +++ b/freebsd/contrib/wpa/src/ap/ieee802_11_shared.c @@ -174,6 +174,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) case 0: /* Bits 0-7 */ if (hapd->iconf->obss_interval) *pos |= 0x01; /* Bit 0 - Coexistence management */ + if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) + *pos |= 0x04; /* Bit 2 - Extended Channel Switching */ break; case 1: /* Bits 8-15 */ if (hapd->conf->proxy_arp) @@ -209,11 +211,21 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) if (hapd->conf->hs20) *pos |= 0x40; /* Bit 46 - WNM-Notification */ #endif /* CONFIG_HS20 */ +#ifdef CONFIG_MBO + if (hapd->conf->mbo_enabled) + *pos |= 0x40; /* Bit 46 - WNM-Notification */ +#endif /* CONFIG_MBO */ break; case 6: /* Bits 48-55 */ if (hapd->conf->ssid.utf8_ssid) *pos |= 0x01; /* Bit 48 - UTF-8 SSID */ break; + case 8: /* Bits 64-71 */ + if (hapd->conf->ftm_responder) + *pos |= 0x40; /* Bit 70 - FTM responder */ + if (hapd->conf->ftm_initiator) + *pos |= 0x80; /* Bit 71 - FTM initiator */ + break; } } @@ -233,6 +245,9 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) len = 1; if (len < 7 && hapd->conf->ssid.utf8_ssid) len = 7; + if (len < 9 && + (hapd->conf->ftm_initiator || hapd->conf->ftm_responder)) + len = 9; #ifdef CONFIG_WNM if (len < 4) len = 4; @@ -241,6 +256,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) if (hapd->conf->hs20 && len < 6) len = 6; #endif /* CONFIG_HS20 */ +#ifdef CONFIG_MBO + if (hapd->conf->mbo_enabled && len < 6) + len = 6; +#endif /* CONFIG_MBO */ if (len < hapd->iface->extended_capa_len) len = hapd->iface->extended_capa_len; if (len == 0) @@ -508,3 +527,62 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid) return pos; } + + +#ifdef CONFIG_MBO + +u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len) +{ + u8 mbo[6], *mbo_pos = mbo; + u8 *pos = eid; + + if (!hapd->conf->mbo_enabled) + return eid; + + *mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND; + *mbo_pos++ = 1; + /* Not Cellular aware */ + *mbo_pos++ = 0; + + if (hapd->mbo_assoc_disallow) { + *mbo_pos++ = MBO_ATTR_ID_ASSOC_DISALLOW; + *mbo_pos++ = 1; + *mbo_pos++ = hapd->mbo_assoc_disallow; + } + + pos += mbo_add_ie(pos, len, mbo, mbo_pos - mbo); + + return pos; +} + + +u8 hostapd_mbo_ie_len(struct hostapd_data *hapd) +{ + if (!hapd->conf->mbo_enabled) + return 0; + + /* + * MBO IE header (6) + Capability Indication attribute (3) + + * Association Disallowed attribute (3) = 12 + */ + return 6 + 3 + (hapd->mbo_assoc_disallow ? 3 : 0); +} + +#endif /* CONFIG_MBO */ + + +void ap_copy_sta_supp_op_classes(struct sta_info *sta, + const u8 *supp_op_classes, + size_t supp_op_classes_len) +{ + if (!supp_op_classes) + return; + os_free(sta->supp_op_classes); + sta->supp_op_classes = os_malloc(1 + supp_op_classes_len); + if (!sta->supp_op_classes) + return; + + sta->supp_op_classes[0] = supp_op_classes_len; + os_memcpy(sta->supp_op_classes + 1, supp_op_classes, + supp_op_classes_len); +} diff --git a/freebsd/contrib/wpa/src/ap/pmksa_cache_auth.h b/freebsd/contrib/wpa/src/ap/pmksa_cache_auth.h index 8b7be129..d8d9c5a2 100644 --- a/freebsd/contrib/wpa/src/ap/pmksa_cache_auth.h +++ b/freebsd/contrib/wpa/src/ap/pmksa_cache_auth.h @@ -17,7 +17,7 @@ struct rsn_pmksa_cache_entry { struct rsn_pmksa_cache_entry *next, *hnext; u8 pmkid[PMKID_LEN]; - u8 pmk[PMK_LEN]; + u8 pmk[PMK_LEN_MAX]; size_t pmk_len; os_time_t expiration; int akmp; /* WPA_KEY_MGMT_* */ @@ -28,11 +28,10 @@ struct rsn_pmksa_cache_entry { struct wpabuf *cui; struct radius_class_data radius_class; u8 eap_type_authsrv; - int vlan_id; + struct vlan_description *vlan_desc; int opportunistic; - u32 acct_multi_session_id_hi; - u32 acct_multi_session_id_lo; + u64 acct_multi_session_id; }; struct rsn_pmksa_cache; @@ -49,7 +48,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( const u8 *pmkid); struct rsn_pmksa_cache_entry * pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, - const u8 *pmk, size_t pmk_len, + const u8 *pmk, size_t pmk_len, const u8 *pmkid, const u8 *kck, size_t kck_len, const u8 *aa, const u8 *spa, int session_timeout, struct eapol_state_machine *eapol, int akmp); @@ -57,11 +56,14 @@ struct rsn_pmksa_cache_entry * pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa, const struct rsn_pmksa_cache_entry *old_entry, const u8 *aa, const u8 *pmkid); -void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, +void pmksa_cache_to_eapol_data(struct hostapd_data *hapd, + struct rsn_pmksa_cache_entry *entry, struct eapol_state_machine *eapol); void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, struct rsn_pmksa_cache_entry *entry); int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa, struct radius_das_attrs *attr); +int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); +void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa); #endif /* PMKSA_CACHE_H */ diff --git a/freebsd/contrib/wpa/src/ap/sta_info.h b/freebsd/contrib/wpa/src/ap/sta_info.h index 420d64e5..099de62d 100644 --- a/freebsd/contrib/wpa/src/ap/sta_info.h +++ b/freebsd/contrib/wpa/src/ap/sta_info.h @@ -12,9 +12,11 @@ #ifdef CONFIG_MESH /* needed for mesh_plink_state enum */ #include "common/defs.h" +#include "common/wpa_common.h" #endif /* CONFIG_MESH */ #include "list.h" +#include "vlan.h" /* STA flags */ #define WLAN_STA_AUTH BIT(0) @@ -45,6 +47,20 @@ #define WLAN_SUPP_RATES_MAX 32 +struct mbo_non_pref_chan_info { + struct mbo_non_pref_chan_info *next; + u8 op_class; + u8 pref; + u8 reason_code; + u8 num_channels; + u8 channels[]; +}; + +struct pending_eapol_rx { + struct wpabuf *buf; + struct os_reltime rx_time; +}; + struct sta_info { struct sta_info *next; /* next entry in sta list */ struct sta_info *hnext; /* next entry in hash table list */ @@ -63,13 +79,22 @@ struct sta_info { enum mesh_plink_state plink_state; u16 peer_lid; u16 my_lid; + u16 peer_aid; u16 mpm_close_reason; int mpm_retries; - u8 my_nonce[32]; - u8 peer_nonce[32]; + u8 my_nonce[WPA_NONCE_LEN]; + u8 peer_nonce[WPA_NONCE_LEN]; u8 aek[32]; /* SHA256 digest length */ - u8 mtk[16]; - u8 mgtk[16]; + u8 mtk[WPA_TK_MAX_LEN]; + size_t mtk_len; + u8 mgtk_rsc[6]; + u8 mgtk_key_id; + u8 mgtk[WPA_TK_MAX_LEN]; + size_t mgtk_len; + u8 igtk_rsc[6]; + u8 igtk[WPA_TK_MAX_LEN]; + size_t igtk_len; + u16 igtk_key_id; u8 sae_auth_retry; #endif /* CONFIG_MESH */ @@ -86,6 +111,8 @@ struct sta_info { unsigned int hs20_deauth_requested:1; unsigned int session_timeout_set:1; unsigned int radius_das_match:1; + unsigned int ecsa_supported:1; + unsigned int added_unassoc:1; u16 auth_alg; @@ -100,17 +127,20 @@ struct sta_info { /* IEEE 802.1X related data */ struct eapol_state_machine *eapol_sm; - u32 acct_session_id_hi; - u32 acct_session_id_lo; + struct pending_eapol_rx *pending_eapol_rx; + + u64 acct_session_id; struct os_reltime acct_session_start; int acct_session_started; int acct_terminate_cause; /* Acct-Terminate-Cause */ int acct_interim_interval; /* Acct-Interim-Interval */ + unsigned int acct_interim_errors; - unsigned long last_rx_bytes; - unsigned long last_tx_bytes; - u32 acct_input_gigawords; /* Acct-Input-Gigawords */ - u32 acct_output_gigawords; /* Acct-Output-Gigawords */ + /* For extending 32-bit driver counters to 64-bit counters */ + u32 last_rx_bytes_hi; + u32 last_rx_bytes_lo; + u32 last_tx_bytes_hi; + u32 last_tx_bytes_lo; u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */ @@ -118,6 +148,7 @@ struct sta_info { struct rsn_preauth_interface *preauth_iface; int vlan_id; /* 0: none, >0: VID */ + struct vlan_description *vlan_desc; int vlan_id_bound; /* updated by ap_sta_bind_vlan() */ /* PSKs from RADIUS authentication server */ struct hostapd_sta_wpa_psk_short *psk; @@ -161,6 +192,7 @@ struct sta_info { #ifdef CONFIG_SAE struct sae_data *sae; + unsigned int mesh_sae_pmksa_caching:1; #endif /* CONFIG_SAE */ u32 session_timeout; /* valid only if session_timeout_set == 1 */ @@ -170,6 +202,22 @@ struct sta_info { u16 last_seq_ctrl; /* Last Authentication/(Re)Association Request/Action frame subtype */ u8 last_subtype; + +#ifdef CONFIG_MBO + u8 cell_capa; /* 0 = unknown (not an MBO STA); otherwise, + * enum mbo_cellular_capa values */ + struct mbo_non_pref_chan_info *non_pref_chan; +#endif /* CONFIG_MBO */ + + u8 *supp_op_classes; /* Supported Operating Classes element, if + * received, starting from the Length field */ + + u8 rrm_enabled_capa[5]; + +#ifdef CONFIG_TAXONOMY + struct wpabuf *probe_ie_taxonomy; + struct wpabuf *assoc_ie_taxonomy; +#endif /* CONFIG_TAXONOMY */ }; @@ -180,7 +228,7 @@ struct sta_info { * 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_DISASSOC_DELAY (3) #define AP_DEAUTH_DELAY (1) /* Number of seconds to keep STA entry with Authenticated flag after it has * been disassociated. */ @@ -220,6 +268,8 @@ 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 ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta, + struct vlan_description *vlan_desc); 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); @@ -235,6 +285,8 @@ static inline int ap_sta_is_authorized(struct sta_info *sta) 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); +void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd, + struct sta_info *sta); int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen); diff --git a/freebsd/contrib/wpa/src/ap/vlan.h b/freebsd/contrib/wpa/src/ap/vlan.h new file mode 100644 index 00000000..af84929d --- /dev/null +++ b/freebsd/contrib/wpa/src/ap/vlan.h @@ -0,0 +1,30 @@ +/* + * hostapd / VLAN definition + * Copyright (c) 2015, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef VLAN_H +#define VLAN_H + +#define MAX_NUM_TAGGED_VLAN 32 + +struct vlan_description { + int notempty; /* 0 : no vlan information present, 1: else */ + int untagged; /* >0 802.1q vid */ + int tagged[MAX_NUM_TAGGED_VLAN]; /* first k items, ascending order */ +}; + +#ifndef CONFIG_NO_VLAN +int vlan_compare(struct vlan_description *a, struct vlan_description *b); +#else /* CONFIG_NO_VLAN */ +static inline int +vlan_compare(struct vlan_description *a, struct vlan_description *b) +{ + return 0; +} +#endif /* CONFIG_NO_VLAN */ + +#endif /* VLAN_H */ diff --git a/freebsd/contrib/wpa/src/ap/wpa_auth.c b/freebsd/contrib/wpa/src/ap/wpa_auth.c index 97d44620..5e0b0bf8 100644 --- a/freebsd/contrib/wpa/src/ap/wpa_auth.c +++ b/freebsd/contrib/wpa/src/ap/wpa_auth.c @@ -46,7 +46,8 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, - const u8 *pmk, struct wpa_ptk *ptk); + const u8 *pmk, unsigned int pmk_len, + struct wpa_ptk *ptk); static void wpa_group_free(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static void wpa_group_get(struct wpa_authenticator *wpa_auth, @@ -829,6 +830,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, struct wpa_ptk PTK; int ok = 0; const u8 *pmk = NULL; + unsigned int pmk_len; for (;;) { if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { @@ -836,10 +838,13 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, sm->p2p_dev_addr, pmk); if (pmk == NULL) break; - } else + pmk_len = PMK_LEN; + } else { pmk = sm->PMK; + pmk_len = sm->pmk_len; + } - wpa_derive_ptk(sm, sm->alt_SNonce, pmk, &PTK); + wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK); if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len) == 0) { @@ -1742,6 +1747,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) #else /* CONFIG_IEEE80211R */ break; #endif /* CONFIG_IEEE80211R */ + case WPA_DRV_STA_REMOVED: + sm->tk_already_set = FALSE; + return 0; } #ifdef CONFIG_IEEE80211R @@ -1921,11 +1929,27 @@ SM_STATE(WPA_PTK, INITPMK) #endif /* CONFIG_IEEE80211R */ if (sm->pmksa) { wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache"); - os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN); + os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len); + sm->pmk_len = sm->pmksa->pmk_len; } else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) { + unsigned int pmk_len; + + if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + pmk_len = PMK_LEN_SUITE_B_192; + else + pmk_len = PMK_LEN; wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine " - "(len=%lu)", (unsigned long) len); - os_memcpy(sm->PMK, msk, PMK_LEN); + "(MSK len=%lu PMK len=%u)", (unsigned long) len, + pmk_len); + if (len < pmk_len) { + wpa_printf(MSG_DEBUG, + "WPA: MSK not long enough (%u) to create PMK (%u)", + (unsigned int) len, (unsigned int) pmk_len); + sm->Disconnect = TRUE; + return; + } + os_memcpy(sm->PMK, msk, pmk_len); + sm->pmk_len = pmk_len; #ifdef CONFIG_IEEE80211R if (len >= 2 * PMK_LEN) { os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN); @@ -1960,6 +1984,7 @@ SM_STATE(WPA_PTK, INITPSK) psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL); if (psk) { os_memcpy(sm->PMK, psk, PMK_LEN); + sm->pmk_len = PMK_LEN; #ifdef CONFIG_IEEE80211R os_memcpy(sm->xxkey, psk, PMK_LEN); sm->xxkey_len = PMK_LEN; @@ -2011,7 +2036,7 @@ SM_STATE(WPA_PTK, PTKSTART) * Calculate PMKID since no PMKSA cache entry was * available with pre-calculated PMKID. */ - rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr, + rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr, sm->addr, &pmkid[2 + RSN_SELECTOR_LEN], wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); } @@ -2023,14 +2048,15 @@ SM_STATE(WPA_PTK, PTKSTART) static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, - const u8 *pmk, struct wpa_ptk *ptk) + const u8 *pmk, unsigned int pmk_len, + struct wpa_ptk *ptk) { #ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) return wpa_auth_derive_ptk_ft(sm, pmk, ptk); #endif /* CONFIG_IEEE80211R */ - return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion", + return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion", sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce, ptk, sm->wpa_key_mgmt, sm->pairwise); } @@ -2041,6 +2067,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) struct wpa_ptk PTK; int ok = 0, psk_found = 0; const u8 *pmk = NULL; + unsigned int pmk_len; SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); sm->EAPOLKeyReceived = FALSE; @@ -2056,10 +2083,13 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) if (pmk == NULL) break; psk_found = 1; - } else + pmk_len = PMK_LEN; + } else { pmk = sm->PMK; + pmk_len = sm->pmk_len; + } - wpa_derive_ptk(sm, sm->SNonce, pmk, &PTK); + wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK); if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, sm->last_rx_eapol_key, @@ -2109,6 +2139,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) * state machine data based on whatever PSK was selected here. */ os_memcpy(sm->PMK, pmk, PMK_LEN); + sm->pmk_len = PMK_LEN; } sm->MICVerified = TRUE; @@ -2287,14 +2318,19 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) pos += wpa_ie_len; #ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { - int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name); + int res; + size_t elen; + + elen = pos - kde; + res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name); if (res < 0) { wpa_printf(MSG_ERROR, "FT: Failed to insert " "PMKR1Name into RSN IE in EAPOL-Key data"); os_free(kde); return; } - pos += res; + pos -= wpa_ie_len; + pos += elen; } #endif /* CONFIG_IEEE80211R */ if (gtk) { @@ -2312,10 +2348,18 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) struct wpa_auth_config *conf; conf = &sm->wpa_auth->conf; - res = wpa_write_ftie(conf, conf->r0_key_holder, - conf->r0_key_holder_len, - NULL, NULL, pos, kde + kde_len - pos, - NULL, 0); + if (sm->assoc_resp_ftie && + kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) { + os_memcpy(pos, sm->assoc_resp_ftie, + 2 + sm->assoc_resp_ftie[1]); + res = 2 + sm->assoc_resp_ftie[1]; + } else { + res = wpa_write_ftie(conf, conf->r0_key_holder, + conf->r0_key_holder_len, + NULL, NULL, pos, + kde + kde_len - pos, + NULL, 0); + } if (res < 0) { wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE " "into EAPOL-Key Key Data"); @@ -3271,13 +3315,21 @@ 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, + unsigned int pmk_len, int session_timeout, struct eapol_state_machine *eapol) { if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 || sm->wpa_auth->conf.disable_pmksa_caching) return -1; - if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN, + if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { + if (pmk_len > PMK_LEN_SUITE_B_192) + pmk_len = PMK_LEN_SUITE_B_192; + } else if (pmk_len > PMK_LEN) { + pmk_len = PMK_LEN; + } + + if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL, sm->PTK.kck, sm->PTK.kck_len, sm->wpa_auth->addr, sm->addr, session_timeout, eapol, sm->wpa_key_mgmt)) @@ -3295,7 +3347,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, if (wpa_auth == NULL) return -1; - if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, + if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL, NULL, 0, wpa_auth->addr, sta_addr, session_timeout, eapol, @@ -3307,12 +3359,12 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr, - const u8 *pmk) + const u8 *pmk, const u8 *pmkid) { if (wpa_auth->conf.disable_pmksa_caching) return -1; - if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, + if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid, NULL, 0, wpa_auth->addr, addr, 0, NULL, WPA_KEY_MGMT_SAE)) @@ -3338,6 +3390,46 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, } +int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf, + size_t len) +{ + if (!wpa_auth || !wpa_auth->pmksa) + return 0; + return pmksa_cache_auth_list(wpa_auth->pmksa, buf, len); +} + + +void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth) +{ + if (wpa_auth && wpa_auth->pmksa) + pmksa_cache_auth_flush(wpa_auth->pmksa); +} + + +struct rsn_pmksa_cache_entry * +wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr) +{ + if (!wpa_auth || !wpa_auth->pmksa) + return NULL; + return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL); +} + + +void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa, + struct wpa_state_machine *sm, + struct wpa_authenticator *wpa_auth, + u8 *pmkid, u8 *pmk) +{ + if (!sm) + return; + + sm->pmksa = pmksa; + os_memcpy(pmk, pmksa->pmk, PMK_LEN); + os_memcpy(pmkid, pmksa->pmkid, PMKID_LEN); + os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmksa->pmkid, PMKID_LEN); +} + + /* * Remove and free the group from wpa_authenticator. This is triggered by a * callback to make sure nobody is currently iterating the group list while it @@ -3416,6 +3508,98 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id) } +/* + * Enforce that the group state machine for the VLAN is running, increase + * reference counter as interface is up. References might have been increased + * even if a negative value is returned. + * Returns: -1 on error (group missing, group already failed); otherwise, 0 + */ +int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id) +{ + struct wpa_group *group; + + if (wpa_auth == NULL) + return 0; + + group = wpa_auth->group; + while (group) { + if (group->vlan_id == vlan_id) + break; + group = group->next; + } + + if (group == NULL) { + group = wpa_auth_add_group(wpa_auth, vlan_id); + if (group == NULL) + return -1; + } + + wpa_printf(MSG_DEBUG, + "WPA: Ensure group state machine running for VLAN ID %d", + vlan_id); + + wpa_group_get(wpa_auth, group); + group->num_setup_iface++; + + if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) + return -1; + + return 0; +} + + +/* + * Decrease reference counter, expected to be zero afterwards. + * returns: -1 on error (group not found, group in fail state) + * -2 if wpa_group is still referenced + * 0 else + */ +int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id) +{ + struct wpa_group *group; + int ret = 0; + + if (wpa_auth == NULL) + return 0; + + group = wpa_auth->group; + while (group) { + if (group->vlan_id == vlan_id) + break; + group = group->next; + } + + if (group == NULL) + return -1; + + wpa_printf(MSG_DEBUG, + "WPA: Try stopping group state machine for VLAN ID %d", + vlan_id); + + if (group->num_setup_iface <= 0) { + wpa_printf(MSG_ERROR, + "WPA: wpa_auth_release_group called more often than wpa_auth_ensure_group for VLAN ID %d, skipping.", + vlan_id); + return -1; + } + group->num_setup_iface--; + + if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) + ret = -1; + + if (group->references > 1) { + wpa_printf(MSG_DEBUG, + "WPA: Cannot stop group state machine for VLAN ID %d as references are still hold", + vlan_id); + ret = -2; + } + + wpa_group_put(wpa_auth, group); + + return ret; +} + + int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) { struct wpa_group *group; diff --git a/freebsd/contrib/wpa/src/ap/wpa_auth.h b/freebsd/contrib/wpa/src/ap/wpa_auth.h index 1b1442f4..97461b02 100644 --- a/freebsd/contrib/wpa/src/ap/wpa_auth.h +++ b/freebsd/contrib/wpa/src/ap/wpa_auth.h @@ -42,10 +42,11 @@ struct ft_rrb_frame { #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 #define FT_R0KH_R1KH_PULL_NONCE_LEN 16 +#define FT_R0KH_R1KH_PULL_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \ + WPA_PMK_NAME_LEN + FT_R1KH_ID_LEN + \ + ETH_ALEN) +#define FT_R0KH_R1KH_PULL_PAD_LEN ((8 - FT_R0KH_R1KH_PULL_DATA_LEN % 8) % 8) struct ft_r0kh_r1kh_pull_frame { u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ @@ -57,14 +58,18 @@ struct ft_r0kh_r1kh_pull_frame { 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 pad[FT_R0KH_R1KH_PULL_PAD_LEN]; /* 8-octet boundary for AES block */ u8 key_wrap_extra[8]; } STRUCT_PACKED; +#define FT_R0KH_R1KH_RESP_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \ + FT_R1KH_ID_LEN + ETH_ALEN + PMK_LEN + \ + WPA_PMK_NAME_LEN + 2) +#define FT_R0KH_R1KH_RESP_PAD_LEN ((8 - FT_R0KH_R1KH_RESP_DATA_LEN % 8) % 8) 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) */ + le16 data_length; /* little endian length of data (78) */ u8 ap_address[ETH_ALEN]; u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN]; /* copied from pull */ @@ -73,14 +78,18 @@ struct ft_r0kh_r1kh_resp_frame { 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 pad[FT_R0KH_R1KH_RESP_PAD_LEN]; /* 8-octet boundary for AES block */ u8 key_wrap_extra[8]; } STRUCT_PACKED; +#define FT_R0KH_R1KH_PUSH_DATA_LEN (4 + FT_R1KH_ID_LEN + ETH_ALEN + \ + WPA_PMK_NAME_LEN + PMK_LEN + \ + WPA_PMK_NAME_LEN + 2) +#define FT_R0KH_R1KH_PUSH_PAD_LEN ((8 - FT_R0KH_R1KH_PUSH_DATA_LEN % 8) % 8) 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) */ + le16 data_length; /* little endian length of data (82) */ u8 ap_address[ETH_ALEN]; /* Encrypted with AES key-wrap */ @@ -92,7 +101,7 @@ struct ft_r0kh_r1kh_push_frame { 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 pad[FT_R0KH_R1KH_PUSH_PAD_LEN]; /* 8-octet boundary for AES block */ u8 key_wrap_extra[8]; } STRUCT_PACKED; @@ -258,7 +267,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, u8 *data, size_t data_len); enum wpa_event { WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH, - WPA_REAUTH_EAPOL, WPA_ASSOC_FT + WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED }; void wpa_remove_ptk(struct wpa_state_machine *sm); int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event); @@ -280,15 +289,25 @@ 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, + unsigned int pmk_len, 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_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr, - const u8 *pmk); + const u8 *pmk, const u8 *pmkid); void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, const u8 *sta_addr); +int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf, + size_t len); +void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth); +struct rsn_pmksa_cache_entry * +wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr); +void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa, + struct wpa_state_machine *sm, + struct wpa_authenticator *wpa_auth, + u8 *pmkid, u8 *pmk); 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); @@ -326,4 +345,7 @@ int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth, struct radius_das_attrs *attr); void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth); +int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id); +int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id); + #endif /* WPA_AUTH_H */ diff --git a/freebsd/contrib/wpa/src/ap/wpa_auth_ft.c b/freebsd/contrib/wpa/src/ap/wpa_auth_ft.c index 19530a31..fe145fad 100644 --- a/freebsd/contrib/wpa/src/ap/wpa_auth_ft.c +++ b/freebsd/contrib/wpa/src/ap/wpa_auth_ft.c @@ -722,11 +722,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, ftie_len = res; pos += res; - os_free(sm->assoc_resp_ftie); - sm->assoc_resp_ftie = os_malloc(ftie_len); - if (sm->assoc_resp_ftie) - os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len); - _ftie = (struct rsn_ftie *) (ftie + 2); if (auth_alg == WLAN_AUTH_FT) _ftie->mic_control[1] = 3; /* Information element count */ @@ -752,6 +747,11 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, _ftie->mic) < 0) wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); + os_free(sm->assoc_resp_ftie); + sm->assoc_resp_ftie = os_malloc(ftie_len); + if (sm->assoc_resp_ftie) + os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len); + return pos; } diff --git a/freebsd/contrib/wpa/src/ap/wpa_auth_i.h b/freebsd/contrib/wpa/src/ap/wpa_auth_i.h index 234d84c8..7fd8f05f 100644 --- a/freebsd/contrib/wpa/src/ap/wpa_auth_i.h +++ b/freebsd/contrib/wpa/src/ap/wpa_auth_i.h @@ -60,7 +60,8 @@ struct wpa_state_machine { u8 SNonce[WPA_NONCE_LEN]; u8 alt_SNonce[WPA_NONCE_LEN]; u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN]; - u8 PMK[PMK_LEN]; + u8 PMK[PMK_LEN_MAX]; + unsigned int pmk_len; struct wpa_ptk PTK; Boolean PTK_valid; Boolean pairwise_set; @@ -172,6 +173,7 @@ struct wpa_group { #endif /* CONFIG_IEEE80211W */ /* Number of references except those in struct wpa_group->next */ unsigned int references; + unsigned int num_setup_iface; }; diff --git a/freebsd/contrib/wpa/src/common/ctrl_iface_common.c b/freebsd/contrib/wpa/src/common/ctrl_iface_common.c new file mode 100644 index 00000000..72f539c4 --- /dev/null +++ b/freebsd/contrib/wpa/src/common/ctrl_iface_common.c @@ -0,0 +1,175 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * Common hostapd/wpa_supplicant ctrl iface code. + * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2015, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" +#include <netdb.h> +#include <sys/un.h> + +#include "utils/common.h" +#include "ctrl_iface_common.h" + +static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len, + struct sockaddr_storage *b, socklen_t b_len) +{ + if (a->ss_family != b->ss_family) + return 1; + + switch (a->ss_family) { +#ifdef CONFIG_CTRL_IFACE_UDP + case AF_INET: + { + struct sockaddr_in *in_a, *in_b; + + in_a = (struct sockaddr_in *) a; + in_b = (struct sockaddr_in *) b; + + if (in_a->sin_port != in_b->sin_port) + return 1; + if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr) + return 1; + break; + } + case AF_INET6: + { + struct sockaddr_in6 *in6_a, *in6_b; + + in6_a = (struct sockaddr_in6 *) a; + in6_b = (struct sockaddr_in6 *) b; + + if (in6_a->sin6_port != in6_b->sin6_port) + return 1; + if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr, + sizeof(in6_a->sin6_addr)) != 0) + return 1; + break; + } +#endif /* CONFIG_CTRL_IFACE_UDP */ +#ifdef CONFIG_CTRL_IFACE_UNIX + case AF_UNIX: + { + struct sockaddr_un *u_a, *u_b; + + u_a = (struct sockaddr_un *) a; + u_b = (struct sockaddr_un *) b; + + if (a_len != b_len || + os_memcmp(u_a->sun_path, u_b->sun_path, + a_len - offsetof(struct sockaddr_un, sun_path)) + != 0) + return 1; + break; + } +#endif /* CONFIG_CTRL_IFACE_UNIX */ + default: + return 1; + } + + return 0; +} + + +void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock, + socklen_t socklen) +{ + switch (sock->ss_family) { +#ifdef CONFIG_CTRL_IFACE_UDP + case AF_INET: + case AF_INET6: + { + char host[NI_MAXHOST] = { 0 }; + char service[NI_MAXSERV] = { 0 }; + + getnameinfo((struct sockaddr *) sock, socklen, + host, sizeof(host), + service, sizeof(service), + NI_NUMERICHOST); + + wpa_printf(level, "%s %s:%s", msg, host, service); + break; + } +#endif /* CONFIG_CTRL_IFACE_UDP */ +#ifdef CONFIG_CTRL_IFACE_UNIX + case AF_UNIX: + { + char addr_txt[200]; + + printf_encode(addr_txt, sizeof(addr_txt), + (u8 *) ((struct sockaddr_un *) sock)->sun_path, + socklen - offsetof(struct sockaddr_un, sun_path)); + wpa_printf(level, "%s %s", msg, addr_txt); + break; + } +#endif /* CONFIG_CTRL_IFACE_UNIX */ + default: + wpa_printf(level, "%s", msg); + break; + } +} + + +int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen) +{ + struct wpa_ctrl_dst *dst; + + dst = os_zalloc(sizeof(*dst)); + if (dst == NULL) + return -1; + os_memcpy(&dst->addr, from, fromlen); + dst->addrlen = fromlen; + dst->debug_level = MSG_INFO; + dl_list_add(ctrl_dst, &dst->list); + + sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen); + return 0; +} + + +int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen) +{ + struct wpa_ctrl_dst *dst; + + dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) { + if (!sockaddr_compare(from, fromlen, + &dst->addr, dst->addrlen)) { + sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached", + from, fromlen); + dl_list_del(&dst->list); + os_free(dst); + return 0; + } + } + + return -1; +} + + +int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen, const char *level) +{ + struct wpa_ctrl_dst *dst; + + wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); + + dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) { + if (!sockaddr_compare(from, fromlen, + &dst->addr, dst->addrlen)) { + sockaddr_print(MSG_DEBUG, + "CTRL_IFACE changed monitor level", + from, fromlen); + dst->debug_level = atoi(level); + return 0; + } + } + + return -1; +} diff --git a/freebsd/contrib/wpa/src/common/ctrl_iface_common.h b/freebsd/contrib/wpa/src/common/ctrl_iface_common.h new file mode 100644 index 00000000..0b6e3e74 --- /dev/null +++ b/freebsd/contrib/wpa/src/common/ctrl_iface_common.h @@ -0,0 +1,38 @@ +/* + * Common hostapd/wpa_supplicant ctrl iface code. + * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2015, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#ifndef CONTROL_IFACE_COMMON_H +#define CONTROL_IFACE_COMMON_H + +#include "utils/list.h" + +/** + * struct wpa_ctrl_dst - Data structure of control interface monitors + * + * This structure is used to store information about registered control + * interface monitors into struct wpa_supplicant. + */ +struct wpa_ctrl_dst { + struct dl_list list; + struct sockaddr_storage addr; + socklen_t addrlen; + int debug_level; + int errors; +}; + +void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock, + socklen_t socklen); + +int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen); +int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen); +int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen, const char *level); + +#endif /* CONTROL_IFACE_COMMON_H */ diff --git a/freebsd/contrib/wpa/src/common/defs.h b/freebsd/contrib/wpa/src/common/defs.h index 6aea3751..4f567945 100644 --- a/freebsd/contrib/wpa/src/common/defs.h +++ b/freebsd/contrib/wpa/src/common/defs.h @@ -312,6 +312,7 @@ enum wpa_ctrl_req_type { WPA_CTRL_REQ_EAP_PASSPHRASE, WPA_CTRL_REQ_SIM, WPA_CTRL_REQ_PSK_PASSPHRASE, + WPA_CTRL_REQ_EXT_CERT_CHECK, NUM_WPA_CTRL_REQS }; @@ -319,13 +320,13 @@ enum wpa_ctrl_req_type { #define EAP_MAX_METHODS 8 enum mesh_plink_state { - PLINK_LISTEN = 1, - PLINK_OPEN_SENT, - PLINK_OPEN_RCVD, + PLINK_IDLE = 1, + PLINK_OPN_SNT, + PLINK_OPN_RCVD, PLINK_CNF_RCVD, PLINK_ESTAB, PLINK_HOLDING, - PLINK_BLOCKED, + PLINK_BLOCKED, /* not defined in the IEEE 802.11 standard */ }; enum set_band { @@ -334,4 +335,10 @@ enum set_band { WPA_SETBAND_2G }; +enum wpa_radio_work_band { + BAND_2_4_GHZ = BIT(0), + BAND_5_GHZ = BIT(1), + BAND_60_GHZ = BIT(2), +}; + #endif /* DEFS_H */ diff --git a/freebsd/contrib/wpa/src/common/eapol_common.h b/freebsd/contrib/wpa/src/common/eapol_common.h index 6958661f..d773348b 100644 --- a/freebsd/contrib/wpa/src/common/eapol_common.h +++ b/freebsd/contrib/wpa/src/common/eapol_common.h @@ -25,7 +25,7 @@ struct ieee802_1x_hdr { struct ieee8023_hdr { u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; - u16 ethertype; + be16 ethertype; } STRUCT_PACKED; #ifdef _MSC_VER diff --git a/freebsd/contrib/wpa/src/common/ieee802_11_common.c b/freebsd/contrib/wpa/src/common/ieee802_11_common.c index ba7ef0a8..286fdcf8 100644 --- a/freebsd/contrib/wpa/src/common/ieee802_11_common.c +++ b/freebsd/contrib/wpa/src/common/ieee802_11_common.c @@ -117,6 +117,11 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, elems->osen = pos; elems->osen_len = elen; break; + case MBO_OUI_TYPE: + /* MBO-OCE */ + elems->mbo = pos; + elems->mbo_len = elen; + break; default: wpa_printf(MSG_MSGDUMP, "Unknown WFA " "information element ignored " @@ -368,6 +373,14 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen; elems->mb_ies.nof_ies++; break; + case WLAN_EID_SUPPORTED_OPERATING_CLASSES: + elems->supp_op_classes = pos; + elems->supp_op_classes_len = elen; + break; + case WLAN_EID_RRM_ENABLED_CAPABILITIES: + elems->rrm_enabled = pos; + elems->rrm_enabled_len = elen; + break; default: unknown++; if (!show_errors) @@ -400,8 +413,8 @@ int ieee802_11_ie_count(const u8 *ies, size_t ies_len) pos = ies; end = ies + ies_len; - while (pos + 2 <= end) { - if (pos + 2 + pos[1] > end) + while (end - pos >= 2) { + if (2 + pos[1] > end - pos) break; count++; pos += 2 + pos[1]; @@ -421,8 +434,8 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, end = ies + ies_len; ie = NULL; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) return NULL; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && WPA_GET_BE32(&pos[2]) == oui_type) { @@ -443,8 +456,8 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, * There may be multiple vendor IEs in the message, so need to * concatenate their data fields. */ - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && WPA_GET_BE32(&pos[2]) == oui_type) @@ -572,7 +585,8 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) { u8 op_class; - return ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, channel); + return ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT, + &op_class, channel); } @@ -581,7 +595,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) * for HT40 and VHT. DFS channels are not covered. * @freq: Frequency (MHz) to convert * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below - * @vht: 0 - non-VHT, 1 - 80 MHz + * @vht: VHT channel width (VHT_CHANWIDTH_*) * @op_class: Buffer for returning operating class * @channel: Buffer for returning channel number * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure @@ -590,6 +604,8 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel, int vht, u8 *op_class, u8 *channel) { + u8 vht_opclass; + /* TODO: more operating classes */ if (sec_channel > 1 || sec_channel < -1) @@ -633,17 +649,32 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, return HOSTAPD_MODE_IEEE80211A; } + switch (vht) { + case VHT_CHANWIDTH_80MHZ: + vht_opclass = 128; + break; + case VHT_CHANWIDTH_160MHZ: + vht_opclass = 129; + break; + case VHT_CHANWIDTH_80P80MHZ: + vht_opclass = 130; + break; + default: + vht_opclass = 0; + break; + } + /* 5 GHz, channels 36..48 */ if (freq >= 5180 && freq <= 5240) { if ((freq - 5000) % 5) return NUM_HOSTAPD_MODES; - if (sec_channel == 1) + if (vht_opclass) + *op_class = vht_opclass; + else if (sec_channel == 1) *op_class = 116; else if (sec_channel == -1) *op_class = 117; - else if (vht) - *op_class = 128; else *op_class = 115; @@ -652,31 +683,40 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, return HOSTAPD_MODE_IEEE80211A; } - /* 5 GHz, channels 149..161 */ - if (freq >= 5745 && freq <= 5805) { + /* 5 GHz, channels 149..169 */ + if (freq >= 5745 && freq <= 5845) { if ((freq - 5000) % 5) return NUM_HOSTAPD_MODES; - if (sec_channel == 1) + if (vht_opclass) + *op_class = vht_opclass; + else if (sec_channel == 1) *op_class = 126; else if (sec_channel == -1) *op_class = 127; - else if (vht) - *op_class = 128; - else + else if (freq <= 5805) *op_class = 124; + else + *op_class = 125; *channel = (freq - 5000) / 5; return HOSTAPD_MODE_IEEE80211A; } - /* 5 GHz, channels 149..169 */ - if (freq >= 5745 && freq <= 5845) { + /* 5 GHz, channels 100..140 */ + if (freq >= 5000 && freq <= 5700) { if ((freq - 5000) % 5) return NUM_HOSTAPD_MODES; - *op_class = 125; + if (vht_opclass) + *op_class = vht_opclass; + else if (sec_channel == 1) + *op_class = 122; + else if (sec_channel == -1) + *op_class = 123; + else + *op_class = 121; *channel = (freq - 5000) / 5; @@ -1147,3 +1187,135 @@ struct wpabuf * mb_ies_by_info(struct mb_ies_info *info) return mb_ies; } + + +const struct oper_class_map global_op_class[] = { + { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP }, + + /* Do not enable HT40 on 2.4 GHz for P2P use for now */ + { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP }, + + { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS, P2P_SUPP }, + + /* + * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center + * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of + * 80 MHz, but currently use the following definition for simplicity + * (these center frequencies are not actual channels, which makes + * wpas_p2p_allow_channel() fail). wpas_p2p_verify_80mhz() should take + * care of removing invalid channels. + */ + { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP }, + { -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP } +}; + + +static enum phy_type ieee80211_phy_type_by_freq(int freq) +{ + enum hostapd_hw_mode hw_mode; + u8 channel; + + hw_mode = ieee80211_freq_to_chan(freq, &channel); + + switch (hw_mode) { + case HOSTAPD_MODE_IEEE80211A: + return PHY_TYPE_OFDM; + case HOSTAPD_MODE_IEEE80211B: + return PHY_TYPE_HRDSSS; + case HOSTAPD_MODE_IEEE80211G: + return PHY_TYPE_ERP; + case HOSTAPD_MODE_IEEE80211AD: + return PHY_TYPE_DMG; + default: + return PHY_TYPE_UNSPECIFIED; + }; +} + + +/* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */ +enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht) +{ + if (vht) + return PHY_TYPE_VHT; + if (ht) + return PHY_TYPE_HT; + + return ieee80211_phy_type_by_freq(freq); +} + + +size_t global_op_class_size = ARRAY_SIZE(global_op_class); + + +/** + * get_ie - Fetch a specified information element from IEs buffer + * @ies: Information elements buffer + * @len: Information elements buffer length + * @eid: Information element identifier (WLAN_EID_*) + * Returns: Pointer to the information element (id field) or %NULL if not found + * + * This function returns the first matching information element in the IEs + * buffer or %NULL in case the element is not found. + */ +const u8 * get_ie(const u8 *ies, size_t len, u8 eid) +{ + const u8 *end; + + if (!ies) + return NULL; + + end = ies + len; + + while (end - ies > 1) { + if (2 + ies[1] > end - ies) + break; + + if (ies[0] == eid) + return ies; + + ies += 2 + ies[1]; + } + + return NULL; +} + + +size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len) +{ + /* + * MBO IE requires 6 bytes without the attributes: EID (1), length (1), + * OUI (3), OUI type (1). + */ + if (len < 6 + attr_len) { + wpa_printf(MSG_DEBUG, + "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu", + len, attr_len); + return 0; + } + + *buf++ = WLAN_EID_VENDOR_SPECIFIC; + *buf++ = attr_len + 4; + WPA_PUT_BE24(buf, OUI_WFA); + buf += 3; + *buf++ = MBO_OUI_TYPE; + os_memcpy(buf, attr, attr_len); + + return 6 + attr_len; +} diff --git a/freebsd/contrib/wpa/src/common/ieee802_11_common.h b/freebsd/contrib/wpa/src/common/ieee802_11_common.h index 55ce0223..42f39096 100644 --- a/freebsd/contrib/wpa/src/common/ieee802_11_common.h +++ b/freebsd/contrib/wpa/src/common/ieee802_11_common.h @@ -9,6 +9,8 @@ #ifndef IEEE802_11_COMMON_H #define IEEE802_11_COMMON_H +#include "defs.h" + #define MAX_NOF_MB_IES_SUPPORTED 5 struct mb_ies_info { @@ -56,9 +58,12 @@ struct ieee802_11_elems { const u8 *bss_max_idle_period; const u8 *ssid_list; const u8 *osen; + const u8 *mbo; const u8 *ampe; const u8 *mic; const u8 *pref_freq_list; + const u8 *supp_op_classes; + const u8 *rrm_enabled; u8 ssid_len; u8 supp_rates_len; @@ -85,9 +90,13 @@ struct ieee802_11_elems { u8 ext_capab_len; u8 ssid_list_len; u8 osen_len; + u8 mbo_len; u8 ampe_len; u8 mic_len; u8 pref_freq_list_len; + u8 supp_op_classes_len; + u8 rrm_enabled_len; + struct mb_ies_info mb_ies; }; @@ -118,6 +127,7 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel, int vht, u8 *op_class, u8 *channel); int ieee80211_is_dfs(int freq); +enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht); int supp_rates_11b_only(struct ieee802_11_elems *elems); int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf, @@ -125,4 +135,22 @@ int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf, struct wpabuf * mb_ies_by_info(struct mb_ies_info *info); const char * fc2str(u16 fc); + +struct oper_class_map { + enum hostapd_hw_mode mode; + u8 op_class; + u8 min_chan; + u8 max_chan; + u8 inc; + enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80 } bw; + enum { P2P_SUPP, NO_P2P_SUPP } p2p; +}; + +extern const struct oper_class_map global_op_class[]; +extern size_t global_op_class_size; + +const u8 * get_ie(const u8 *ies, size_t len, u8 eid); + +size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len); + #endif /* IEEE802_11_COMMON_H */ diff --git a/freebsd/contrib/wpa/src/common/ieee802_11_defs.h b/freebsd/contrib/wpa/src/common/ieee802_11_defs.h index 44530ce3..d453aec7 100644 --- a/freebsd/contrib/wpa/src/common/ieee802_11_defs.h +++ b/freebsd/contrib/wpa/src/common/ieee802_11_defs.h @@ -94,8 +94,13 @@ #define WLAN_CAPABILITY_PBCC BIT(6) #define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7) #define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8) +#define WLAN_CAPABILITY_QOS BIT(9) #define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10) +#define WLAN_CAPABILITY_APSD BIT(11) +#define WLAN_CAPABILITY_RADIO_MEASUREMENT BIT(12) #define WLAN_CAPABILITY_DSSS_OFDM BIT(13) +#define WLAN_CAPABILITY_DELAYED_BLOCK_ACK BIT(14) +#define WLAN_CAPABILITY_IMM_BLOCK_ACK BIT(15) /* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */ #define WLAN_STATUS_SUCCESS 0 @@ -247,6 +252,7 @@ #define WLAN_EID_TIMEOUT_INTERVAL 56 #define WLAN_EID_RIC_DATA 57 #define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59 +#define WLAN_EID_EXT_CHANSWITCH_ANN 60 #define WLAN_EID_HT_OPERATION 61 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 #define WLAN_EID_WAPI 68 @@ -360,6 +366,16 @@ /* byte 1 (out of 5) */ #define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0) #define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1) +/* byte 2 (out of 5) */ +#define WLAN_RRM_CAPS_LCI_MEASUREMENT BIT(4) +/* byte 5 (out of 5) */ +#define WLAN_RRM_CAPS_FTM_RANGE_REPORT BIT(2) + +/* + * IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 (Fine Timing Measurement Range + * request) - Minimum AP count + */ +#define WLAN_RRM_RANGE_REQ_MAX_MIN_AP 15 /* Timeout Interval Type */ #define WLAN_TIMEOUT_REASSOC_DEADLINE 1 @@ -407,7 +423,12 @@ enum anqp_info_id { ANQP_AP_LOCATION_PUBLIC_URI = 267, ANQP_DOMAIN_NAME = 268, ANQP_EMERGENCY_ALERT_URI = 269, + ANQP_TDLS_CAPABILITY = 270, ANQP_EMERGENCY_NAI = 271, + ANQP_NEIGHBOR_REPORT = 272, + ANQP_VENUE_URL = 277, + ANQP_ADVICE_OF_CHARGE = 278, + ANQP_LOCAL_CONTENT = 279, ANQP_VENDOR_SPECIFIC = 56797 }; @@ -442,6 +463,48 @@ enum nai_realm_eap_cred_type { NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10 }; +/* + * IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for + * measurement requests + */ +enum measure_type { + MEASURE_TYPE_BASIC = 0, + MEASURE_TYPE_CCA = 1, + MEASURE_TYPE_RPI_HIST = 2, + MEASURE_TYPE_CHANNEL_LOAD = 3, + MEASURE_TYPE_NOISE_HIST = 4, + MEASURE_TYPE_BEACON = 5, + MEASURE_TYPE_FRAME = 6, + MEASURE_TYPE_STA_STATISTICS = 7, + MEASURE_TYPE_LCI = 8, + MEASURE_TYPE_TRANSMIT_STREAM = 9, + MEASURE_TYPE_MULTICAST_DIAG = 10, + MEASURE_TYPE_LOCATION_CIVIC = 11, + MEASURE_TYPE_LOCATION_ID = 12, + MEASURE_TYPE_DIRECTIONAL_CHAN_QUALITY = 13, + MEASURE_TYPE_DIRECTIONAL_MEASURE = 14, + MEASURE_TYPE_DIRECTIONAL_STATS = 15, + MEASURE_TYPE_FTM_RANGE = 16, + MEASURE_TYPE_MEASURE_PAUSE = 255, +}; + +/* IEEE Std 802.11-2012 Table 8-71 - Location subject definition */ +enum location_subject { + LOCATION_SUBJECT_LOCAL = 0, + LOCATION_SUBJECT_REMOTE = 1, + LOCATION_SUBJECT_3RD_PARTY = 2, +}; + +/* + * IEEE P802.11-REVmc/D5.0 Table 9-94 - Optional subelement IDs for LCI request + */ +enum lci_req_subelem { + LCI_REQ_SUBELEM_AZIMUTH_REQ = 1, + LCI_REQ_SUBELEM_ORIGINATOR_MAC_ADDR = 2, + LCI_REQ_SUBELEM_TARGET_MAC_ADDR = 3, + LCI_REQ_SUBELEM_MAX_AGE = 4, +}; + #ifdef _MSC_VER #pragma pack(push, 1) #endif /* _MSC_VER */ @@ -516,10 +579,7 @@ struct ieee80211_mgmt { * FH Params, DS Params, CF Params, IBSS Params, TIM */ u8 variable[]; } STRUCT_PACKED beacon; - struct { - /* only variable items: SSID, Supported rates */ - u8 variable[0]; - } STRUCT_PACKED probe_req; + /* probe_req: only variable items: SSID, Supported rates */ struct { u8 timestamp[8]; le16 beacon_int; @@ -625,12 +685,19 @@ struct ieee80211_mgmt { u8 action; u8 variable[]; } STRUCT_PACKED fst_action; + struct { + u8 action; + u8 dialog_token; + u8 variable[]; + } STRUCT_PACKED rrm; } u; } STRUCT_PACKED action; } u; } STRUCT_PACKED; +#define IEEE80211_MAX_MMPDU_SIZE 2304 + /* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */ #define IEEE80211_HT_MCS_MASK_LEN 10 @@ -690,9 +757,14 @@ struct ieee80211_ampe_ie { u8 selected_pairwise_suite[4]; u8 local_nonce[32]; u8 peer_nonce[32]; - u8 mgtk[16]; - u8 key_rsc[8]; - u8 key_expiration[4]; + /* Followed by + * Key Replay Counter[8] (optional) + * (only in Mesh Group Key Inform/Acknowledge frames) + * GTKdata[variable] (optional) + * (MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]) + * IGTKdata[variable] (optional) + * (Key ID[2], IPN[6], IGTK[variable] in IGTK KDE format) + */ } STRUCT_PACKED; #ifdef _MSC_VER @@ -879,6 +951,8 @@ struct ieee80211_ampe_ie { #define WFD_OUI_TYPE 10 #define HS20_IE_VENDOR_TYPE 0x506f9a10 #define OSEN_IE_VENDOR_TYPE 0x506f9a12 +#define MBO_IE_VENDOR_TYPE 0x506f9a16 +#define MBO_OUI_TYPE 22 #define WMM_OUI_TYPE 2 #define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 @@ -1021,6 +1095,95 @@ enum wmm_ac { #define HS20_DEAUTH_REASON_CODE_BSS 0 #define HS20_DEAUTH_REASON_CODE_ESS 1 +/* MBO v0.0_r19, 4.2: MBO Attributes */ +/* Table 4-5: MBO Attributes */ +enum mbo_attr_id { + MBO_ATTR_ID_AP_CAPA_IND = 1, + MBO_ATTR_ID_NON_PREF_CHAN_REPORT = 2, + MBO_ATTR_ID_CELL_DATA_CAPA = 3, + MBO_ATTR_ID_ASSOC_DISALLOW = 4, + MBO_ATTR_ID_CELL_DATA_PREF = 5, + MBO_ATTR_ID_TRANSITION_REASON = 6, + MBO_ATTR_ID_TRANSITION_REJECT_REASON = 7, + MBO_ATTR_ID_ASSOC_RETRY_DELAY = 8, +}; + +/* MBO v0.0_r19, 4.2.1: MBO AP Capability Indication Attribute */ +/* Table 4-7: MBO AP Capability Indication Field Values */ +#define MBO_AP_CAPA_CELL_AWARE BIT(6) + +/* MBO v0.0_r19, 4.2.2: Non-preferred Channel Report Attribute */ +/* Table 4-10: Reason Code Field Values */ +enum mbo_non_pref_chan_reason { + MBO_NON_PREF_CHAN_REASON_UNSPECIFIED = 0, + MBO_NON_PREF_CHAN_REASON_RSSI = 1, + MBO_NON_PREF_CHAN_REASON_EXT_INTERFERENCE = 2, + MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE = 3, +}; + +/* MBO v0.0_r19, 4.2.3: Cellular Data Capabilities Attribute */ +/* Table 4-13: Cellular Data Connectivity Field */ +enum mbo_cellular_capa { + MBO_CELL_CAPA_AVAILABLE = 1, + MBO_CELL_CAPA_NOT_AVAILABLE = 2, + MBO_CELL_CAPA_NOT_SUPPORTED = 3, +}; + +/* MBO v0.0_r19, 4.2.4: Association Disallowed Attribute */ +/* Table 4-15: Reason Code Field Values */ +enum mbo_assoc_disallow_reason { + MBO_ASSOC_DISALLOW_REASON_UNSPECIFIED = 1, + MBO_ASSOC_DISALLOW_REASON_MAX_STA = 2, + MBO_ASSOC_DISALLOW_REASON_AIR_INTERFERENCE = 3, + MBO_ASSOC_DISALLOW_REASON_AUTH_SERVER_OVERLOAD = 4, + MBO_ASSOC_DISALLOW_REASON_LOW_RSSI = 5, +}; + +/* MBO v0.0_r19, 4.2.5: Cellular Data Connection Preference Attribute */ +/* Table 4-17: Cellular Preference Field Values */ +enum mbo_cell_pref { + MBO_CELL_PREF_EXCLUDED = 0, + MBO_CELL_PREF_NO_USE = 1, + MBO_CELL_PREF_USE = 255 +}; + +/* MBO v0.0_r19, 4.2.6: Transition Reason Code Attribute */ +/* Table 4-19: Transition Reason Code Field Values */ +enum mbo_transition_reason { + MBO_TRANSITION_REASON_UNSPECIFIED = 0, + MBO_TRANSITION_REASON_FRAME_LOSS = 1, + MBO_TRANSITION_REASON_DELAY = 2, + MBO_TRANSITION_REASON_BANDWIDTH = 3, + MBO_TRANSITION_REASON_LOAD_BALANCE = 4, + MBO_TRANSITION_REASON_RSSI = 5, + MBO_TRANSITION_REASON_RETRANSMISSIONS = 6, + MBO_TRANSITION_REASON_INTERFERENCE = 7, + MBO_TRANSITION_REASON_GRAY_ZONE = 8, + MBO_TRANSITION_REASON_PREMIUM_AP = 9, +}; + +/* MBO v0.0_r19, 4.2.7: Transition Rejection Reason Code Attribute */ +/* Table 4-21: Transition Rejection Reason Code Field Values */ +enum mbo_transition_reject_reason { + MBO_TRANSITION_REJECT_REASON_UNSPECIFIED = 0, + MBO_TRANSITION_REJECT_REASON_FRAME_LOSS = 1, + MBO_TRANSITION_REJECT_REASON_DELAY = 2, + MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY = 3, + MBO_TRANSITION_REJECT_REASON_RSSI = 4, + MBO_TRANSITION_REJECT_REASON_INTERFERENCE = 5, + MBO_TRANSITION_REJECT_REASON_SERVICES = 6, +}; + +/* MBO v0.0_r19, 4.4: WNM-Notification vendor subelements */ +enum wfa_wnm_notif_subelem_id { + WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT = 2, + WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA = 3, +}; + +/* MBO v0.0_r25, 4.3: MBO ANQP-elements */ +#define MBO_ANQP_OUI_TYPE 0x12 +#define MBO_ANQP_SUBTYPE_CELL_CONN_PREF 1 + /* Wi-Fi Direct (P2P) */ #define P2P_OUI_TYPE 9 @@ -1178,6 +1341,14 @@ enum wifi_display_subelem { #define MESH_PATH_PROTOCOL_VENDOR 255 #define MESH_PATH_METRIC_AIRTIME 1 #define MESH_PATH_METRIC_VENDOR 255 +/* IEEE 802.11s - Mesh Capability */ +#define MESH_CAP_ACCEPT_ADDITIONAL_PEER BIT(0) +#define MESH_CAP_MCCA_SUPPORTED BIT(1) +#define MESH_CAP_MCCA_ENABLED BIT(2) +#define MESH_CAP_FORWARDING BIT(3) +#define MESH_CAP_MBCA_ENABLED BIT(4) +#define MESH_CAP_TBTT_ADJUSTING BIT(5) +#define MESH_CAP_MESH_PS_LEVEL BIT(6) enum plink_action_field { PLINK_OPEN = 1, @@ -1280,14 +1451,25 @@ enum bss_trans_mgmt_status_code { WNM_BSS_TM_REJECT_LEAVING_ESS = 8 }; +/* + * IEEE P802.11-REVmc/D5.0 Table 9-150 - Optional subelement IDs for + * neighbor report + */ #define WNM_NEIGHBOR_TSF 1 #define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2 #define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3 #define WNM_NEIGHBOR_BSS_TERMINATION_DURATION 4 #define WNM_NEIGHBOR_BEARING 5 +#define WNM_NEIGHBOR_WIDE_BW_CHAN 6 +#define WNM_NEIGHBOR_MEASUREMENT_REPORT 39 +#define WNM_NEIGHBOR_HT_CAPAB 45 +#define WNM_NEIGHBOR_HT_OPER 61 +#define WNM_NEIGHBOR_SEC_CHAN_OFFSET 62 #define WNM_NEIGHBOR_MEASUREMENT_PILOT 66 #define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES 70 #define WNM_NEIGHBOR_MULTIPLE_BSSID 71 +#define WNM_NEIGHBOR_VHT_CAPAB 191 +#define WNM_NEIGHBOR_VHT_OPER 192 /* QoS action */ enum qos_action { @@ -1356,6 +1538,8 @@ struct tpc_report { u8 link_margin; } STRUCT_PACKED; +#define RRM_CAPABILITIES_IE_LEN 5 + /* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */ struct rrm_link_measurement_request { u8 dialog_token; @@ -1375,8 +1559,6 @@ struct rrm_link_measurement_report { u8 variable[0]; } STRUCT_PACKED; -#define SSID_MAX_LEN 32 - /* IEEE Std 802.11ad-2012 - Multi-band element */ struct multi_band_ie { u8 eid; /* WLAN_EID_MULTI_BAND */ @@ -1433,4 +1615,49 @@ enum fst_action { FST_ACTION_ON_CHANNEL_TUNNEL = 5, }; +/* IEEE Std 802.11ac-2013, Annex C - dot11PHYType */ +enum phy_type { + PHY_TYPE_UNSPECIFIED = 0, + PHY_TYPE_FHSS = 1, + PHY_TYPE_DSSS = 2, + PHY_TYPE_IRBASEBAND = 3, + PHY_TYPE_OFDM = 4, + PHY_TYPE_HRDSSS = 5, + PHY_TYPE_ERP = 6, + PHY_TYPE_HT = 7, + PHY_TYPE_DMG = 8, + PHY_TYPE_VHT = 9, +}; + +/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */ +/* BSSID Information Field */ +#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0) +#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1) +#define NEI_REP_BSSID_INFO_AP_REACHABLE (BIT(0) | BIT(1)) +#define NEI_REP_BSSID_INFO_SECURITY BIT(2) +#define NEI_REP_BSSID_INFO_KEY_SCOPE BIT(3) +#define NEI_REP_BSSID_INFO_SPECTRUM_MGMT BIT(4) +#define NEI_REP_BSSID_INFO_QOS BIT(5) +#define NEI_REP_BSSID_INFO_APSD BIT(6) +#define NEI_REP_BSSID_INFO_RM BIT(7) +#define NEI_REP_BSSID_INFO_DELAYED_BA BIT(8) +#define NEI_REP_BSSID_INFO_IMM_BA BIT(9) +#define NEI_REP_BSSID_INFO_MOBILITY_DOMAIN BIT(10) +#define NEI_REP_BSSID_INFO_HT BIT(11) +#define NEI_REP_BSSID_INFO_VHT BIT(12) +#define NEI_REP_BSSID_INFO_FTM BIT(13) + +/* + * IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information + * subfields. + * Note: These definitions are not the same as other VHT_CHANWIDTH_*. + */ +enum nr_chan_width { + NR_CHAN_WIDTH_20 = 0, + NR_CHAN_WIDTH_40 = 1, + NR_CHAN_WIDTH_80 = 2, + NR_CHAN_WIDTH_160 = 3, + NR_CHAN_WIDTH_80P80 = 4, +}; + #endif /* IEEE802_11_DEFS_H */ diff --git a/freebsd/contrib/wpa/src/common/qca-vendor.h b/freebsd/contrib/wpa/src/common/qca-vendor.h index 28985f51..adaec890 100644 --- a/freebsd/contrib/wpa/src/common/qca-vendor.h +++ b/freebsd/contrib/wpa/src/common/qca-vendor.h @@ -89,6 +89,102 @@ enum qca_radiotap_vendor_ids { * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: Event used by driver, * which supports DFS offloading, to indicate a radar pattern has been * detected. The channel is now unusable. + * + * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START: Command used to + * start the P2P Listen offload function in device and pass the listen + * channel, period, interval, count, device types, and vendor specific + * information elements to the device driver and firmware. + * Uses the attributes defines in + * enum qca_wlan_vendor_attr_p2p_listen_offload. + * + * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: Command/event used to + * indicate stop request/response of the P2P Listen offload function in + * device. As an event, it indicates either the feature stopped after it + * was already running or feature has actually failed to start. Uses the + * attributes defines in enum qca_wlan_vendor_attr_p2p_listen_offload. + * + * @QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH: After AP starts + * beaconing, this sub command provides the driver, the frequencies on the + * 5 GHz band to check for any radar activity. Driver selects one channel + * from this priority list provided through + * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST and starts + * to check for radar activity on it. If no radar activity is detected + * during the channel availability check period, driver internally switches + * to the selected frequency of operation. If the frequency is zero, driver + * internally selects a channel. The status of this conditional switch is + * indicated through an event using the same sub command through + * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS. Attributes are + * listed in qca_wlan_vendor_attr_sap_conditional_chan_switch. + * + * @QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND: Set GPIO pins. This uses the + * attributes defined in enum qca_wlan_gpio_attr. + * + * @QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY: Fetch hardware capabilities. + * This uses @QCA_WLAN_VENDOR_ATTR_GET_HW_CAPABILITY to indicate which + * capabilities are to be fetched and other + * enum qca_wlan_vendor_attr_get_hw_capability attributes to return the + * requested capabilities. + * + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT: Link layer statistics extension. + * enum qca_wlan_vendor_attr_ll_stats_ext attributes are used with this + * command and event. + * + * @QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA: Get capabilities for + * indoor location features. Capabilities are reported in + * QCA_WLAN_VENDOR_ATTR_LOC_CAPA. + * + * @QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION: Start an FTM + * (fine timing measurement) session with one or more peers. + * Specify Session cookie in QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE and + * peer information in QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS. + * On success, 0 or more QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT + * events will be reported, followed by + * QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE event to indicate + * end of session. + * Refer to IEEE P802.11-REVmc/D7.0, 11.24.6 + * + * @QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION: Abort a running session. + * A QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE will be reported with + * status code indicating session was aborted. + * + * @QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT: Event with measurement + * results for one peer. Results are reported in + * QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS. + * + * @QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE: Event triggered when + * FTM session is finished, either successfully or aborted by + * request. + * + * @QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER: Configure FTM responder + * mode. QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE specifies whether + * to enable or disable the responder. LCI/LCR reports can be + * configured with QCA_WLAN_VENDOR_ATTR_FTM_LCI and + * QCA_WLAN_VENDOR_ATTR_FTM_LCR. Can be called multiple + * times to update the LCI/LCR reports. + * + * @QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS: Perform a standalone AOA (angle of + * arrival) measurement with a single peer. Specify peer MAC address in + * QCA_WLAN_VENDOR_ATTR_MAC_ADDR and measurement type in + * QCA_WLAN_VENDOR_ATTR_AOA_TYPE. Measurement result is reported in + * QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT event. + * + * @QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS: Abort an AOA measurement. Specify + * peer MAC address in QCA_WLAN_VENDOR_ATTR_MAC_ADDR. + * + * @QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT: Event that reports + * the AOA measurement result. + * Peer MAC address reported in QCA_WLAN_VENDOR_ATTR_MAC_ADDR. + * success/failure status is reported in + * QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS. + * Measurement data is reported in QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT. + * The antenna array(s) used in the measurement are reported in + * QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK. + * + * @QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST: Encrypt/decrypt the given + * data as per the given parameters. + * + * @QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI: Get antenna RSSI value for a + * specific chain. */ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, @@ -140,7 +236,11 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED = 58, QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED = 59, QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60, - /* 61-90 - reserved for QCA */ + /* 61-73 - reserved for QCA */ + /* Wi-Fi configuration subcommands */ + QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74, + QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION = 75, + /* 76-90 - reserved for QCA */ QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91, QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92, QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93, @@ -156,6 +256,35 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST = 103, QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL = 104, QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105, + QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN = 106, + QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE = 107, + QCA_NL80211_VENDOR_SUBCMD_OTA_TEST = 108, + QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109, + /* 110..114 - reserved for QCA */ + QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115, + /* 116..117 - reserved for QCA */ + QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG = 118, + QCA_NL80211_VENDOR_SUBCMD_TSF = 119, + QCA_NL80211_VENDOR_SUBCMD_WISA = 120, + /* 121 - reserved for QCA */ + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START = 122, + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP = 123, + QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH = 124, + QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND = 125, + QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY = 126, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT = 127, + /* FTM/indoor location subcommands */ + QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128, + QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129, + QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION = 130, + QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT = 131, + QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE = 132, + QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER = 133, + QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS = 134, + QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS = 135, + QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT = 136, + QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST = 137, + QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI = 138, }; @@ -185,6 +314,84 @@ enum qca_wlan_vendor_attr { QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11, /* Unsigned 32-bit value from enum qca_set_band. */ QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12, + /* Dummy (NOP) attribute for 64 bit padding */ + QCA_WLAN_VENDOR_ATTR_PAD = 13, + /* Unique FTM session cookie (Unsigned 64 bit). Specified in + * QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION. Reported in + * the session in QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT and + * QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE. + */ + QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE = 14, + /* Indoor location capabilities, returned by + * QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA. + * see enum qca_wlan_vendor_attr_loc_capa. + */ + QCA_WLAN_VENDOR_ATTR_LOC_CAPA = 15, + /* Array of nested attributes containing information about each peer + * in FTM measurement session. See enum qca_wlan_vendor_attr_peer_info + * for supported attributes for each peer. + */ + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS = 16, + /* Array of nested attributes containing measurement results for + * one or more peers, reported by the + * QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT event. + * See enum qca_wlan_vendor_attr_peer_result for list of supported + * attributes. + */ + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS = 17, + /* Flag attribute for enabling or disabling responder functionality. */ + QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE = 18, + /* Used in the QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER + * command to specify the LCI report that will be sent by + * the responder during a measurement exchange. The format is + * defined in IEEE P802.11-REVmc/D7.0, 9.4.2.22.10. + */ + QCA_WLAN_VENDOR_ATTR_FTM_LCI = 19, + /* Used in the QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER + * command to specify the location civic report that will + * be sent by the responder during a measurement exchange. + * The format is defined in IEEE P802.11-REVmc/D7.0, 9.4.2.22.13. + */ + QCA_WLAN_VENDOR_ATTR_FTM_LCR = 20, + /* Session/measurement completion status code, + * reported in QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE and + * QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT + * see enum qca_vendor_attr_loc_session_status. + */ + QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS = 21, + /* Initial dialog token used by responder (0 if not specified), + * unsigned 8 bit value. + */ + QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN = 22, + /* AOA measurement type. Requested in QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS + * and optionally in QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION if + * AOA measurements are needed as part of an FTM session. + * Reported by QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT. See + * enum qca_wlan_vendor_attr_aoa_type. + */ + QCA_WLAN_VENDOR_ATTR_AOA_TYPE = 23, + /* A bit mask (unsigned 32 bit value) of antenna arrays used + * by indoor location measurements. Refers to the antenna + * arrays described by QCA_VENDOR_ATTR_LOC_CAPA_ANTENNA_ARRAYS. + */ + QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK = 24, + /* AOA measurement data. Its contents depends on the AOA measurement + * type and antenna array mask: + * QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: array of U16 values, + * phase of the strongest CIR path for each antenna in the measured + * array(s). + * QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: array of 2 U16 + * values, phase and amplitude of the strongest CIR path for each + * antenna in the measured array(s). + */ + QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25, + /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command + * to specify the chain number (unsigned 32 bit value) to inquire + * the corresponding antenna RSSI value */ + QCA_WLAN_VENDOR_ATTR_CHAIN_INDEX = 26, + /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command + * to report the specific antenna RSSI value (unsigned 32 bit value) */ + QCA_WLAN_VENDOR_ATTR_CHAIN_RSSI = 27, /* keep last */ QCA_WLAN_VENDOR_ATTR_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1, @@ -205,12 +412,50 @@ enum qca_wlan_vendor_attr_roam_auth { QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS, /* keep last */ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX = QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST - 1 }; +enum qca_wlan_vendor_attr_p2p_listen_offload { + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INVALID = 0, + /* A 32-bit unsigned value; the P2P listen frequency (MHz); must be one + * of the social channels. + */ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL, + /* A 32-bit unsigned value; the P2P listen offload period (ms). + */ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD, + /* A 32-bit unsigned value; the P2P listen interval duration (ms). + */ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL, + /* A 32-bit unsigned value; number of interval times the firmware needs + * to run the offloaded P2P listen operation before it stops. + */ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT, + /* An array of arbitrary binary data with one or more 8-byte values. + * The device types include both primary and secondary device types. + */ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES, + /* An array of unsigned 8-bit characters; vendor information elements. + */ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE, + /* A 32-bit unsigned value; a control flag to indicate whether listen + * results need to be flushed to wpa_supplicant. + */ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG, + /* A 8-bit unsigned value; reason code for P2P listen offload stop + * event. + */ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX = + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1 +}; + enum qca_wlan_vendor_attr_acs_offload { QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0, QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL, @@ -247,11 +492,21 @@ enum qca_wlan_vendor_acs_hw_mode { * after roaming, rather than having the user space wpa_supplicant do it. * @QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY: Device supports automatic * band selection based on channel selection results. + * @QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS: Device supports + * simultaneous off-channel operations. + * @QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD: Device supports P2P + * Listen offload; a mechanism where the station's firmware takes care of + * responding to incoming Probe Request frames received from other P2P + * Devices whilst in Listen state, rather than having the user space + * wpa_supplicant do it. Information from received P2P requests are + * forwarded from firmware to host whenever the host processor wakes up. * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits */ enum qca_wlan_vendor_features { QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0, QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1, + QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS = 2, + QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD = 3, NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */ }; @@ -324,6 +579,67 @@ enum qca_set_band { QCA_SETBAND_2G, }; +/** + * enum qca_access_policy - Access control policy + * + * Access control policy is applied on the configured IE + * (QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE). + * To be set with QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY. + * + * @QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED: Deny Wi-Fi connections which match + * the specific configuration (IE) set, i.e., allow all the + * connections which do not match the configuration. + * @QCA_ACCESS_POLICY_DENY_UNLESS_LISTED: Accept Wi-Fi connections which match + * the specific configuration (IE) set, i.e., deny all the + * connections which do not match the configuration. + */ +enum qca_access_policy { + QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED, + QCA_ACCESS_POLICY_DENY_UNLESS_LISTED, +}; + +/** + * enum qca_vendor_attr_get_tsf: Vendor attributes for TSF capture + * @QCA_WLAN_VENDOR_ATTR_TSF_CMD: enum qca_tsf_operation (u32) + * @QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE: Unsigned 64 bit TSF timer value + * @QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE: Unsigned 64 bit Synchronized + * SOC timer value at TSF capture + */ +enum qca_vendor_attr_tsf_cmd { + QCA_WLAN_VENDOR_ATTR_TSF_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TSF_CMD, + QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE, + QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE, + QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TSF_MAX = + QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST - 1 +}; + +/** + * enum qca_tsf_operation: TSF driver commands + * @QCA_TSF_CAPTURE: Initiate TSF Capture + * @QCA_TSF_GET: Get TSF capture value + * @QCA_TSF_SYNC_GET: Initiate TSF capture and return with captured value + */ +enum qca_tsf_cmd { + QCA_TSF_CAPTURE, + QCA_TSF_GET, + QCA_TSF_SYNC_GET, +}; + +/** + * enum qca_vendor_attr_wisa_cmd + * @QCA_WLAN_VENDOR_ATTR_WISA_MODE: WISA mode value (u32) + * WISA setup vendor commands + */ +enum qca_vendor_attr_wisa_cmd { + QCA_WLAN_VENDOR_ATTR_WISA_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_WISA_MODE, + QCA_WLAN_VENDOR_ATTR_WISA_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_WISA_MAX = + QCA_WLAN_VENDOR_ATTR_WISA_AFTER_LAST - 1 +}; + /* IEEE 802.11 Vendor Specific elements */ /** @@ -349,9 +665,926 @@ enum qca_set_band { * * This vendor element may be included in GO Negotiation Request, P2P * Invitation Request, and Provision Discovery Request frames. + * + * @QCA_VENDOR_ELEM_HE_CAPAB: HE Capabilities element. + * This element can be used for pre-standard publication testing of HE + * before P802.11ax draft assigns the element ID. The payload of this + * vendor specific element is defined by the latest P802.11ax draft. + * Please note that the draft is still work in progress and this element + * payload is subject to change. + * + * @QCA_VENDOR_ELEM_HE_OPER: HE Operation element. + * This element can be used for pre-standard publication testing of HE + * before P802.11ax draft assigns the element ID. The payload of this + * vendor specific element is defined by the latest P802.11ax draft. + * Please note that the draft is still work in progress and this element + * payload is subject to change. */ enum qca_vendor_element_id { QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST = 0, + QCA_VENDOR_ELEM_HE_CAPAB = 1, + QCA_VENDOR_ELEM_HE_OPER = 2, +}; + +/** + * enum qca_wlan_vendor_attr_scan - Specifies vendor scan attributes + * + * @QCA_WLAN_VENDOR_ATTR_SCAN_IE: IEs that should be included as part of scan + * @QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES: Nested unsigned 32-bit attributes + * with frequencies to be scanned (in MHz) + * @QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS: Nested attribute with SSIDs to be scanned + * @QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES: Nested array attribute of supported + * rates to be included + * @QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE: flag used to send probe requests + * at non CCK rate in 2GHz band + * @QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS: Unsigned 32-bit scan flags + * @QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE: Unsigned 64-bit cookie provided by the + * driver for the specific scan request + * @QCA_WLAN_VENDOR_ATTR_SCAN_STATUS: Unsigned 8-bit status of the scan + * request decoded as in enum scan_status + * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC: 6-byte MAC address to use when randomisation + * scan flag is set + * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK: 6-byte MAC address mask to be used with + * randomisation + */ +enum qca_wlan_vendor_attr_scan { + QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0, + QCA_WLAN_VENDOR_ATTR_SCAN_IE, + QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES, + QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS, + QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES, + QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE, + QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, + QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, + QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, + QCA_WLAN_VENDOR_ATTR_SCAN_MAC, + QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK, + QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SCAN_MAX = + QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1 +}; + +/** + * enum scan_status - Specifies the valid values the vendor scan attribute + * QCA_WLAN_VENDOR_ATTR_SCAN_STATUS can take + * + * @VENDOR_SCAN_STATUS_NEW_RESULTS: implies the vendor scan is successful with + * new scan results + * @VENDOR_SCAN_STATUS_ABORTED: implies the vendor scan was aborted in-between + */ +enum scan_status { + VENDOR_SCAN_STATUS_NEW_RESULTS, + VENDOR_SCAN_STATUS_ABORTED, + VENDOR_SCAN_STATUS_MAX, +}; + +/** + * enum qca_vendor_attr_ota_test - Specifies the values for vendor + * command QCA_NL80211_VENDOR_SUBCMD_OTA_TEST + * @QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE: enable ota test + */ +enum qca_vendor_attr_ota_test { + QCA_WLAN_VENDOR_ATTR_OTA_TEST_INVALID, + /* 8-bit unsigned value to indicate if OTA test is enabled */ + QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_OTA_TEST_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX = + QCA_WLAN_VENDOR_ATTR_OTA_TEST_AFTER_LAST - 1 +}; + +/** + * enum qca_vendor_attr_txpower_scale - vendor sub commands index + * + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE: scaling value + */ +enum qca_vendor_attr_txpower_scale { + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_INVALID, + /* 8-bit unsigned value to indicate the scaling of tx power */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX = + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST - 1 +}; + +/** + * enum qca_vendor_attr_txpower_decr_db - Attributes for TX power decrease + * + * These attributes are used with QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB. + */ +enum qca_vendor_attr_txpower_decr_db { + QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_INVALID, + /* 8-bit unsigned value to indicate the reduction of TX power in dB for + * a virtual interface. */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_MAX = + QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_AFTER_LAST - 1 +}; + +/* Attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION and + * QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION subcommands. + */ +enum qca_wlan_vendor_attr_config { + QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID = 0, + /* Unsigned 32-bit value to set the DTIM period. + * Whether the wifi chipset wakes at every dtim beacon or a multiple of + * the DTIM period. If DTIM is set to 3, the STA shall wake up every 3 + * DTIM beacons. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_DTIM = 1, + /* Unsigned 32-bit value to set the wifi_iface stats averaging factor + * used to calculate statistics like average the TSF offset or average + * number of frame leaked. + * For instance, upon Beacon frame reception: + * current_avg = ((beacon_TSF - TBTT) * factor + previous_avg * (0x10000 - factor) ) / 0x10000 + * For instance, when evaluating leaky APs: + * current_avg = ((num frame received within guard time) * factor + previous_avg * (0x10000 - factor)) / 0x10000 + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR = 2, + /* Unsigned 32-bit value to configure guard time, i.e., when + * implementing IEEE power management based on frame control PM bit, how + * long the driver waits before shutting down the radio and after + * receiving an ACK frame for a Data frame with PM bit set. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME = 3, + /* Unsigned 32-bit value to change the FTM capability dynamically */ + QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT = 4, + /* Unsigned 16-bit value to configure maximum TX rate dynamically */ + QCA_WLAN_VENDOR_ATTR_CONF_TX_RATE = 5, + /* Unsigned 32-bit value to configure the number of continuous + * Beacon Miss which shall be used by the firmware to penalize + * the RSSI. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_PENALIZE_AFTER_NCONS_BEACON_MISS = 6, + /* Unsigned 8-bit value to configure the channel avoidance indication + * behavior. Firmware to send only one indication and ignore duplicate + * indications when set to avoid multiple Apps wakeups. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND = 7, + /* 8-bit unsigned value to configure the maximum TX MPDU for + * aggregation. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION = 8, + /* 8-bit unsigned value to configure the maximum RX MPDU for + * aggregation. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION = 9, + /* 8-bit unsigned value to configure the Non aggregrate/11g sw + * retry threshold (0 disable, 31 max). */ + QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY = 10, + /* 8-bit unsigned value to configure the aggregrate sw + * retry threshold (0 disable, 31 max). */ + QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY = 11, + /* 8-bit unsigned value to configure the MGMT frame + * retry threshold (0 disable, 31 max). */ + QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY = 12, + /* 8-bit unsigned value to configure the CTRL frame + * retry threshold (0 disable, 31 max). */ + QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY = 13, + /* 8-bit unsigned value to configure the propagation delay for + * 2G/5G band (0~63, units in us) */ + QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY = 14, + /* Unsigned 32-bit value to configure the number of unicast TX fail + * packet count. The peer is disconnected once this threshold is + * reached. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT = 15, + /* Attribute used to set scan default IEs to the driver. + * + * These IEs can be used by scan operations that will be initiated by + * the driver/firmware. + * + * For further scan requests coming to the driver, these IEs should be + * merged with the IEs received along with scan request coming to the + * driver. If a particular IE is present in the scan default IEs but not + * present in the scan request, then that IE should be added to the IEs + * sent in the Probe Request frames for that scan request. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES = 16, + /* Unsigned 32-bit attribute for generic commands */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND = 17, + /* Unsigned 32-bit value attribute for generic commands */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_VALUE = 18, + /* Unsigned 32-bit data attribute for generic command response */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA = 19, + /* Unsigned 32-bit length attribute for + * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH = 20, + /* Unsigned 32-bit flags attribute for + * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS = 21, + /* Unsigned 32-bit, defining the access policy. + * See enum qca_access_policy. Used with + * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY = 22, + /* Sets the list of full set of IEs for which a specific access policy + * has to be applied. Used along with + * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY to control the access. + * Zero length payload can be used to clear this access constraint. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST = 23, + /* Unsigned 32-bit, specifies the interface index (netdev) for which the + * corresponding configurations are applied. If the interface index is + * not specified, the configurations are attributed to the respective + * wiphy. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX = 24, + /* 8-bit unsigned value to trigger QPower: 1-Enable, 0-Disable */ + QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER = 25, + /* 8-bit unsigned value to configure the driver and below layers to + * ignore the assoc disallowed set by APs while connecting + * 1-Ignore, 0-Don't ignore */ + QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED = 26, + /* 32-bit unsigned value to trigger antenna diversity features: + * 1-Enable, 0-Disable */ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA = 27, + /* 32-bit unsigned value to configure specific chain antenna */ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN = 28, + /* 32-bit unsigned value to trigger cycle selftest + * 1-Enable, 0-Disable */ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST = 29, + /* 32-bit unsigned to configure the cycle time of selftest + * the unit is micro-second */ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL = 30, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration + */ +enum qca_wlan_vendor_attr_sap_config { + QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0, + /* 1 - reserved for QCA */ + /* List of frequencies on which AP is expected to operate. + * This is irrespective of ACS configuration. This list is a priority + * based one and is looked for before the AP is created to ensure the + * best concurrency sessions (avoid MCC and use DBS/SCC) co-exist in + * the system. + */ + QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2, + + QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_sap_conditional_chan_switch - Parameters for AP + * conditional channel switch + */ +enum qca_wlan_vendor_attr_sap_conditional_chan_switch { + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_INVALID = 0, + /* Priority based frequency list (an array of u32 values in host byte + * order) */ + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST = 1, + /* Status of the conditional switch (u32). + * 0: Success, Non-zero: Failure + */ + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS = 2, + + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX = + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_gpio_attr - Parameters for GPIO configuration + */ +enum qca_wlan_gpio_attr { + QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INVALID = 0, + /* Unsigned 32-bit attribute for GPIO command */ + QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND, + /* Unsigned 32-bit attribute for GPIO PIN number to configure */ + QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM, + /* Unsigned 32-bit attribute for GPIO value to configure */ + QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE, + /* Unsigned 32-bit attribute for GPIO pull type */ + QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE, + /* Unsigned 32-bit attribute for GPIO interrupt mode */ + QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST, + QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX = + QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability + */ +enum qca_wlan_vendor_attr_get_hw_capability { + QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_INVALID, + /* Antenna isolation + * An attribute used in the response. + * The content of this attribute is encoded in a byte array. Each byte + * value is an antenna isolation value. The array length is the number + * of antennas. + */ + QCA_WLAN_VENDOR_ATTR_ANTENNA_ISOLATION, + /* Request HW capability + * An attribute used in the request. + * The content of this attribute is a u32 array for one or more of + * hardware capabilities (attribute IDs) that are being requested. Each + * u32 value has a value from this + * enum qca_wlan_vendor_attr_get_hw_capability + * identifying which capabilities are requested. + */ + QCA_WLAN_VENDOR_ATTR_GET_HW_CAPABILITY, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_MAX = + QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ll_stats_ext - Attributes for MAC layer monitoring + * offload which is an extension for LL_STATS. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD: Monitoring period. Unit in ms. + * If MAC counters do not exceed the threshold, FW will report monitored + * link layer counters periodically as this setting. The first report is + * always triggered by this timer. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD: It is a percentage (1-99). + * For each MAC layer counter, FW holds two copies. One is the current value. + * The other is the last report. Once a current counter's increment is larger + * than the threshold, FW will indicate that counter to host even if the + * monitoring timer does not expire. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG: Peer STA power state change + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID: TID of MSDU + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU: Count of MSDU with the same + * failure code. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS: TX failure code + * 1: TX packet discarded + * 2: No ACK + * 3: Postpone + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS: peer MAC address + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE: Peer STA current state + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL: Global threshold. + * Threshold for all monitored parameters. If per counter dedicated threshold + * is not enabled, this threshold will take effect. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE: Indicate what triggers this + * event, PERORID_TIMEOUT == 1, THRESH_EXCEED == 0. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID: interface ID + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID: peer ID + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP: bitmap for TX counters + * Bit0: TX counter unit in MSDU + * Bit1: TX counter unit in MPDU + * Bit2: TX counter unit in PPDU + * Bit3: TX counter unit in byte + * Bit4: Dropped MSDUs + * Bit5: Dropped Bytes + * Bit6: MPDU retry counter + * Bit7: MPDU failure counter + * Bit8: PPDU failure counter + * Bit9: MPDU aggregation counter + * Bit10: MCS counter for ACKed MPDUs + * Bit11: MCS counter for Failed MPDUs + * Bit12: TX Delay counter + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP: bitmap for RX counters + * Bit0: MAC RX counter unit in MPDU + * Bit1: MAC RX counter unit in byte + * Bit2: PHY RX counter unit in PPDU + * Bit3: PHY RX counter unit in byte + * Bit4: Disorder counter + * Bit5: Retry counter + * Bit6: Duplication counter + * Bit7: Discard counter + * Bit8: MPDU aggregation size counter + * Bit9: MCS counter + * Bit10: Peer STA power state change (wake to sleep) counter + * Bit11: Peer STA power save counter, total time in PS mode + * Bit12: Probe request counter + * Bit13: Other management frames counter + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP: bitmap for CCA + * Bit0: Idle time + * Bit1: TX time + * Bit2: time RX in current bss + * Bit3: Out of current bss time + * Bit4: Wireless medium busy time + * Bit5: RX in bad condition time + * Bit6: TX in bad condition time + * Bit7: time wlan card not available + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP: bitmap for signal + * Bit0: Per channel SNR counter + * Bit1: Per channel noise floor counter + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM: number of peers + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM: number of channels + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_AC_RX_NUM: number of RX stats + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS: per channel BSS CCA stats + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER: container for per PEER stats + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU: Number of total TX MSDUs + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU: Number of total TX MPDUs + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU: Number of total TX PPDUs + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES: bytes of TX data + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP: Number of dropped TX packets + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES: Bytes dropped + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY: waiting time without an ACK + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK: number of MPDU not-ACKed + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK: number of PPDU not-ACKed + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM: + * aggregation stats buffer length + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM: length of mcs stats + * buffer for ACKed MPDUs. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM: length of mcs stats + * buffer for failed MPDUs. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE: + * length of delay stats array. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR: TX aggregation stats + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS: MCS stats for ACKed MPDUs + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS: MCS stats for failed MPDUs + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY: tx delay stats + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU: MPDUs received + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES: bytes received + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU: PPDU received + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES: PPDU bytes received + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST: packets lost + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY: number of RX packets + * flagged as retransmissions + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP: number of RX packets + * flagged as duplicated + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD: number of RX + * packets discarded + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM: length of RX aggregation + * stats buffer. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM: length of RX mcs + * stats buffer. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS: RX mcs stats buffer + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR: aggregation stats buffer + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES: times STAs go to sleep + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION: STAs' total sleep time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ: number of probe + * requests received + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT: number of other mgmt + * frames received + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME: Percentage of idle time + * there is no TX, nor RX, nor interference. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME: percentage of time + * transmitting packets. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME: percentage of time + * for receiving. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY: percentage of time + * interference detected. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD: percentage of time + * receiving packets with errors. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD: percentage of time + * TX no-ACK. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL: percentage of time + * the chip is unable to work in normal conditions. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME: percentage of time + * receiving packets in current BSS. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME: percentage of time + * receiving packets not in current BSS. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM: number of antennas + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL: + * This is a container for per antenna signal stats. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR: per antenna SNR value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF: per antenna NF value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON: RSSI of beacon + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON: SNR of beacon + */ +enum qca_wlan_vendor_attr_ll_stats_ext { + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_INVALID = 0, + + /* Attributes for configurations */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD, + + /* Peer STA power state change */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG, + + /* TX failure event */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS, + + /* MAC counters */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER, + + /* Sub-attributes for PEER_AC_TX */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY, + + /* Sub-attributes for PEER_AC_RX */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT, + + /* Sub-attributes for CCA_BSS */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL, + + /* sub-attribute for BSS_RX_TIME */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME, + + /* Sub-attributes for PEER_SIGNAL */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF, + + /* Sub-attributes for IFACE_BSS */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST - 1 +}; + +/* Attributes for FTM commands and events */ + +/** + * enum qca_wlan_vendor_attr_loc_capa - Indoor location capabilities + * + * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS: Various flags. See + * enum qca_wlan_vendor_attr_loc_capa_flags. + * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS: Maximum number + * of measurement sessions that can run concurrently. + * Default is one session (no session concurrency). + * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS: The total number of unique + * peers that are supported in running sessions. For example, + * if the value is 8 and maximum number of sessions is 2, you can + * have one session with 8 unique peers, or 2 sessions with 4 unique + * peers each, and so on. + * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP: Maximum number + * of bursts per peer, as an exponent (2^value). Default is 0, + * meaning no multi-burst support. + * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST: Maximum number + * of measurement exchanges allowed in a single burst. + * @QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES: Supported AOA measurement + * types. A bit mask (unsigned 32 bit value), each bit corresponds + * to an AOA type as defined by enum qca_vendor_attr_aoa_type. + */ +enum qca_wlan_vendor_attr_loc_capa { + QCA_WLAN_VENDOR_ATTR_LOC_CAPA_INVALID, + QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS, + QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS, + QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS, + QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP, + QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST, + QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LOC_CAPA_MAX = + QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_loc_capa_flags: Indoor location capability flags + * + * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER: Set if driver + * can be configured as an FTM responder (for example, an AP that + * services FTM requests). QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER + * will be supported if set. + * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR: Set if driver + * can run FTM sessions. QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION + * will be supported if set. +* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP: Set if FTM responder + * supports immediate (ASAP) response. + * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA: Set if driver supports standalone + * AOA measurement using QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS. + * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM: Set if driver supports + * requesting AOA measurements as part of an FTM session. + */ +enum qca_wlan_vendor_attr_loc_capa_flags { + QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER = 1 << 0, + QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR = 1 << 1, + QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP = 1 << 2, + QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA = 1 << 3, + QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM = 1 << 4, +}; + +/** + * enum qca_wlan_vendor_attr_ftm_peer_info: Information about + * a single peer in a measurement session. + * + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR: The MAC address of the peer. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS: Various flags related + * to measurement. See enum qca_wlan_vendor_attr_ftm_peer_meas_flags. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS: Nested attribute of + * FTM measurement parameters, as specified by IEEE P802.11-REVmc/D7.0 + * 9.4.2.167. See enum qca_wlan_vendor_attr_ftm_meas_param for + * list of supported attributes. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID: Initial token ID for + * secure measurement. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD: Request AOA + * measurement every <value> bursts. If 0 or not specified, + * AOA measurements will be disabled for this peer. + */ +enum qca_wlan_vendor_attr_ftm_peer_info { + QCA_WLAN_VENDOR_ATTR_FTM_PEER_INVALID, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX = + QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ftm_peer_meas_flags: Measurement request flags, + * per-peer + * + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP: If set, request + * immediate (ASAP) response from peer. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI: If set, request + * LCI report from peer. The LCI report includes the absolute + * location of the peer in "official" coordinates (similar to GPS). + * See IEEE P802.11-REVmc/D7.0, 11.24.6.7 for more information. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR: If set, request + * Location civic report from peer. The LCR includes the location + * of the peer in free-form format. See IEEE P802.11-REVmc/D7.0, + * 11.24.6.7 for more information. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE: If set, + * request a secure measurement. + * QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID must also be provided. + */ +enum qca_wlan_vendor_attr_ftm_peer_meas_flags { + QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP = 1 << 0, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI = 1 << 1, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR = 1 << 2, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE = 1 << 3, +}; + +/** + * enum qca_wlan_vendor_attr_ftm_meas_param: Measurement parameters + * + * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST: Number of measurements + * to perform in a single burst. + * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP: Number of bursts to + * perform, specified as an exponent (2^value). + * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION: Duration of burst + * instance, as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167. + * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD: Time between bursts, + * as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167. Must + * be larger than QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION. + */ +enum qca_wlan_vendor_attr_ftm_meas_param { + QCA_WLAN_VENDOR_ATTR_FTM_PARAM_INVALID, + QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST, + QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP, + QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION, + QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX = + QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ftm_peer_result: Per-peer results + * + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR: MAC address of the reported + * peer. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS: Status of measurement + * request for this peer. + * See enum qca_wlan_vendor_attr_ftm_peer_result_status. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS: Various flags related + * to measurement results for this peer. + * See enum qca_wlan_vendor_attr_ftm_peer_result_flags. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS: Specified when + * request failed and peer requested not to send an additional request + * for this number of seconds. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI: LCI report when received + * from peer. In the format specified by IEEE P802.11-REVmc/D7.0, + * 9.4.2.22.10. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR: Location civic report when + * received from peer. In the format specified by IEEE P802.11-REVmc/D7.0, + * 9.4.2.22.13. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS: Reported when peer + * overridden some measurement request parameters. See + * enum qca_wlan_vendor_attr_ftm_meas_param. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS: AOA measurement + * for this peer. Same contents as @QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS: Array of measurement + * results. Each entry is a nested attribute defined + * by enum qca_wlan_vendor_attr_ftm_meas. + */ +enum qca_wlan_vendor_attr_ftm_peer_result { + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_INVALID, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAX = + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ftm_peer_result_status + * + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK: Request sent ok and results + * will be provided. Peer may have overridden some measurement parameters, + * in which case overridden parameters will be report by + * QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAM attribute. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE: Peer is incapable + * of performing the measurement request. No more results will be sent + * for this peer in this session. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED: Peer reported request + * failed, and requested not to send an additional request for number + * of seconds specified by QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS + * attribute. + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID: Request validation + * failed. Request was not sent over the air. + */ +enum qca_wlan_vendor_attr_ftm_peer_result_status { + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED, + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID, +}; + +/** + * enum qca_wlan_vendor_attr_ftm_peer_result_flags: Various flags + * for measurement result, per-peer + * + * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE: If set, + * measurement completed for this peer. No more results will be reported + * for this peer in this session. + */ +enum qca_wlan_vendor_attr_ftm_peer_result_flags { + QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE = 1 << 0, +}; + +/** + * enum qca_vendor_attr_loc_session_status: Session completion status code + * + * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK: Session completed + * successfully. + * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED: Session aborted + * by request. + * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID: Session request + * was invalid and was not started. + * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED: Session had an error + * and did not complete normally (for example out of resources). + */ +enum qca_vendor_attr_loc_session_status { + QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK, + QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED, + QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID, + QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED, +}; + +/** + * enum qca_wlan_vendor_attr_ftm_meas: Single measurement data + * + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1: Time of departure (TOD) of FTM packet as + * recorded by responder, in picoseconds. + * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information. + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2: Time of arrival (TOA) of FTM packet at + * initiator, in picoseconds. + * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information. + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3: TOD of ACK packet as recorded by + * initiator, in picoseconds. + * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information. + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4: TOA of ACK packet at + * responder, in picoseconds. + * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information. + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI: RSSI (signal level) as recorded + * during this measurement exchange. Optional and will be provided if + * the hardware can measure it. + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR: TOD error reported by + * responder. Not always provided. + * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information. + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR: TOA error reported by + * responder. Not always provided. + * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information. + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR: TOD error measured by + * initiator. Not always provided. + * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information. + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR: TOA error measured by + * initiator. Not always provided. + * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information. + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD: Dummy attribute for padding. + */ +enum qca_wlan_vendor_attr_ftm_meas { + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INVALID, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_MAX = + QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_aoa_type - AOA measurement type + * + * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: Phase of the strongest + * CIR (channel impulse response) path for each antenna. + * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: Phase and amplitude + * of the strongest CIR path for each antenna. + */ +enum qca_wlan_vendor_attr_aoa_type { + QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE, + QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP, + QCA_WLAN_VENDOR_ATTR_AOA_TYPE_MAX +}; + +/** + * enum qca_wlan_vendor_attr_encryption_test - Attributes to + * validate encryption engine + * + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION: Flag attribute. + * This will be included if the request is for decryption; if not included, + * the request is treated as a request for encryption by default. + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER: Unsigned 32-bit value + * indicating the key cipher suite. Takes same values as + * NL80211_ATTR_KEY_CIPHER. + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID: Unsigned 8-bit value + * Key Id to be used for encryption + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK: Array of 8-bit values. + * Key (TK) to be used for encryption/decryption + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN: Array of 8-bit values. + * Packet number to be specified for encryption/decryption + * 6 bytes for TKIP/CCMP/GCMP. + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA: Array of 8-bit values + * representing the 802.11 packet (header + payload + FCS) that + * needs to be encrypted/decrypted. + * Encrypted/decrypted response from the driver will also be sent + * to userspace with the same attribute. + */ +enum qca_wlan_vendor_attr_encryption_test { + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX = + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST - 1 }; #endif /* QCA_VENDOR_H */ diff --git a/freebsd/contrib/wpa/src/common/sae.h b/freebsd/contrib/wpa/src/common/sae.h index c07026cd..a4270bc2 100644 --- a/freebsd/contrib/wpa/src/common/sae.h +++ b/freebsd/contrib/wpa/src/common/sae.h @@ -45,6 +45,7 @@ struct sae_data { enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state; u16 send_confirm; u8 pmk[SAE_PMK_LEN]; + u8 pmkid[SAE_PMKID_LEN]; struct crypto_bignum *peer_commit_scalar; int group; int sync; diff --git a/freebsd/contrib/wpa/src/common/version.h b/freebsd/contrib/wpa/src/common/version.h index a5cc5b7b..75e5c6e0 100644 --- a/freebsd/contrib/wpa/src/common/version.h +++ b/freebsd/contrib/wpa/src/common/version.h @@ -5,6 +5,10 @@ #define VERSION_STR_POSTFIX "" #endif /* VERSION_STR_POSTFIX */ -#define VERSION_STR "2.5" VERSION_STR_POSTFIX +#ifndef GIT_VERSION_STR_POSTFIX +#define GIT_VERSION_STR_POSTFIX "" +#endif /* GIT_VERSION_STR_POSTFIX */ + +#define VERSION_STR "2.6" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX #endif /* VERSION_H */ diff --git a/freebsd/contrib/wpa/src/common/wpa_common.c b/freebsd/contrib/wpa/src/common/wpa_common.c index f2c2d56d..f1802c36 100644 --- a/freebsd/contrib/wpa/src/common/wpa_common.c +++ b/freebsd/contrib/wpa/src/common/wpa_common.c @@ -294,38 +294,47 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, pos = ie + sizeof(struct rsn_ftie); end = ie + ie_len; - while (pos + 2 <= end && pos + 2 + pos[1] <= end) { - switch (pos[0]) { + while (end - pos >= 2) { + u8 id, len; + + id = *pos++; + len = *pos++; + if (len > end - pos) + break; + + switch (id) { case FTIE_SUBELEM_R1KH_ID: - if (pos[1] != FT_R1KH_ID_LEN) { - wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID " - "length in FTIE: %d", pos[1]); + if (len != FT_R1KH_ID_LEN) { + wpa_printf(MSG_DEBUG, + "FT: Invalid R1KH-ID length in FTIE: %d", + len); return -1; } - parse->r1kh_id = pos + 2; + parse->r1kh_id = pos; break; case FTIE_SUBELEM_GTK: - parse->gtk = pos + 2; - parse->gtk_len = pos[1]; + parse->gtk = pos; + parse->gtk_len = len; break; case FTIE_SUBELEM_R0KH_ID: - if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) { - wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID " - "length in FTIE: %d", pos[1]); + if (len < 1 || len > FT_R0KH_ID_MAX_LEN) { + wpa_printf(MSG_DEBUG, + "FT: Invalid R0KH-ID length in FTIE: %d", + len); return -1; } - parse->r0kh_id = pos + 2; - parse->r0kh_id_len = pos[1]; + parse->r0kh_id = pos; + parse->r0kh_id_len = len; break; #ifdef CONFIG_IEEE80211W case FTIE_SUBELEM_IGTK: - parse->igtk = pos + 2; - parse->igtk_len = pos[1]; + parse->igtk = pos; + parse->igtk_len = len; break; #endif /* CONFIG_IEEE80211W */ } - pos += 2 + pos[1]; + pos += len; } return 0; @@ -347,11 +356,18 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, pos = ies; end = ies + ies_len; - while (pos + 2 <= end && pos + 2 + pos[1] <= end) { - switch (pos[0]) { + while (end - pos >= 2) { + u8 id, len; + + id = *pos++; + len = *pos++; + if (len > end - pos) + break; + + switch (id) { case WLAN_EID_RSN: - parse->rsn = pos + 2; - parse->rsn_len = pos[1]; + parse->rsn = pos; + parse->rsn_len = len; ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, parse->rsn_len + 2, &data); @@ -364,32 +380,32 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, parse->rsn_pmkid = data.pmkid; break; case WLAN_EID_MOBILITY_DOMAIN: - if (pos[1] < sizeof(struct rsn_mdie)) + if (len < sizeof(struct rsn_mdie)) return -1; - parse->mdie = pos + 2; - parse->mdie_len = pos[1]; + parse->mdie = pos; + parse->mdie_len = len; break; case WLAN_EID_FAST_BSS_TRANSITION: - if (pos[1] < sizeof(*ftie)) + if (len < sizeof(*ftie)) return -1; - ftie = (const struct rsn_ftie *) (pos + 2); + ftie = (const struct rsn_ftie *) pos; prot_ie_count = ftie->mic_control[1]; - if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) + if (wpa_ft_parse_ftie(pos, len, parse) < 0) return -1; break; case WLAN_EID_TIMEOUT_INTERVAL: - if (pos[1] != 5) + if (len != 5) break; - parse->tie = pos + 2; - parse->tie_len = pos[1]; + parse->tie = pos; + parse->tie_len = len; break; case WLAN_EID_RIC_DATA: if (parse->ric == NULL) - parse->ric = pos; + parse->ric = pos - 2; break; } - pos += 2 + pos[1]; + pos += len; } if (prot_ie_count == 0) @@ -418,13 +434,15 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, } /* Determine the end of the RIC IE(s) */ - pos = parse->ric; - while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && - prot_ie_count) { - prot_ie_count--; - pos += 2 + pos[1]; + if (parse->ric) { + pos = parse->ric; + while (end - pos >= 2 && 2 + pos[1] <= end - pos && + prot_ie_count) { + prot_ie_count--; + pos += 2 + pos[1]; + } + parse->ric_len = pos - parse->ric; } - parse->ric_len = pos - parse->ric; if (prot_ie_count) { wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " "frame", (int) prot_ie_count); @@ -584,8 +602,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, if (left >= RSN_SELECTOR_LEN) { data->group_cipher = rsn_selector_to_bitfield(pos); if (!wpa_cipher_valid_group(data->group_cipher)) { - wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x", - __func__, data->group_cipher); + wpa_printf(MSG_DEBUG, + "%s: invalid group cipher 0x%x (%08x)", + __func__, data->group_cipher, + WPA_GET_BE32(pos)); return -1; } pos += RSN_SELECTOR_LEN; @@ -673,9 +693,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, if (left >= 4) { data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) { - wpa_printf(MSG_DEBUG, "%s: Unsupported management " - "group cipher 0x%x", __func__, - data->mgmt_group_cipher); + wpa_printf(MSG_DEBUG, + "%s: Unsupported management group cipher 0x%x (%08x)", + __func__, data->mgmt_group_cipher, + WPA_GET_BE32(pos)); return -10; } pos += RSN_SELECTOR_LEN; @@ -1165,6 +1186,8 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto) "WPA2-PSK" : "WPA-PSK"; case WPA_KEY_MGMT_NONE: return "NONE"; + case WPA_KEY_MGMT_WPA_NONE: + return "WPA-NONE"; case WPA_KEY_MGMT_IEEE8021X_NO_WPA: return "IEEE 802.1X (no WPA)"; #ifdef CONFIG_IEEE80211R @@ -1263,13 +1286,13 @@ int wpa_compare_rsn_ie(int ft_initial_assoc, #ifdef CONFIG_IEEE80211R -int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) +int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid) { u8 *start, *end, *rpos, *rend; int added = 0; start = ies; - end = ies + ies_len; + end = ies + *ies_len; while (start < end) { if (*start == WLAN_EID_RSN) @@ -1322,11 +1345,29 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) added += 2 + PMKID_LEN; start[1] += 2 + PMKID_LEN; } else { - /* PMKID-Count was included; use it */ - if (WPA_GET_LE16(rpos) != 0) { - wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " - "in RSN IE in EAPOL-Key data"); + u16 num_pmkid; + + if (rend - rpos < 2) return -1; + num_pmkid = WPA_GET_LE16(rpos); + /* PMKID-Count was included; use it */ + if (num_pmkid != 0) { + u8 *after; + + if (num_pmkid * PMKID_LEN > rend - rpos - 2) + return -1; + /* + * PMKID may have been included in RSN IE in + * (Re)Association Request frame, so remove the old + * PMKID(s) first before adding the new one. + */ + wpa_printf(MSG_DEBUG, + "FT: Remove %u old PMKID(s) from RSN IE", + num_pmkid); + after = rpos + 2 + num_pmkid * PMKID_LEN; + os_memmove(rpos + 2, after, rend - after); + start[1] -= num_pmkid * PMKID_LEN; + added -= num_pmkid * PMKID_LEN; } WPA_PUT_LE16(rpos, 1); rpos += 2; @@ -1339,7 +1380,9 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " "(PMKID inserted)", start, 2 + start[1]); - return added; + *ies_len += added; + + return 0; } #endif /* CONFIG_IEEE80211R */ diff --git a/freebsd/contrib/wpa/src/common/wpa_common.h b/freebsd/contrib/wpa/src/common/wpa_common.h index a04e7593..1021ccb0 100644 --- a/freebsd/contrib/wpa/src/common/wpa_common.h +++ b/freebsd/contrib/wpa/src/common/wpa_common.h @@ -12,6 +12,8 @@ /* IEEE 802.11i */ #define PMKID_LEN 16 #define PMK_LEN 32 +#define PMK_LEN_SUITE_B_192 48 +#define PMK_LEN_MAX 48 #define WPA_REPLAY_COUNTER_LEN 8 #define WPA_NONCE_LEN 32 #define WPA_KEY_RSC_LEN 8 @@ -419,7 +421,7 @@ u32 wpa_akm_to_suite(int akm); int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len); -int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid); +int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid); struct wpa_ft_ies { const u8 *mdie; diff --git a/freebsd/contrib/wpa/src/common/wpa_ctrl.h b/freebsd/contrib/wpa/src/common/wpa_ctrl.h index 3de46823..4dcba81d 100644 --- a/freebsd/contrib/wpa/src/common/wpa_ctrl.h +++ b/freebsd/contrib/wpa/src/common/wpa_ctrl.h @@ -76,6 +76,21 @@ extern "C" { #define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE " /** Regulatory domain channel */ #define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE " +/** Channel switch (followed by freq=<MHz> and other channel parameters) */ +#define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH " + +/** IP subnet status change notification + * + * When using an offloaded roaming mechanism where driver/firmware takes care + * of roaming and IP subnet validation checks post-roaming, this event can + * indicate whether IP subnet has changed. + * + * The event has a status=<0/1/2> parameter where + * 0 = unknown + * 1 = IP subnet unchanged (can continue to use the old IP address) + * 2 = IP subnet changed (need to get a new IP address) + */ +#define WPA_EVENT_SUBNET_STATUS_UPDATE "CTRL-EVENT-SUBNET-STATUS-UPDATE " /** RSN IBSS 4-way handshakes completed with specified peer */ #define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED " @@ -174,6 +189,7 @@ extern "C" { #define P2P_EVENT_SERV_ASP_RESP "P2P-SERV-ASP-RESP " #define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED " #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT " +#define P2P_EVENT_INVITATION_ACCEPTED "P2P-INVITATION-ACCEPTED " #define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED " #define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id=" #define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE " @@ -212,6 +228,11 @@ extern "C" { /* parameters: <addr> <result> */ #define ANQP_QUERY_DONE "ANQP-QUERY-DONE " +#define RX_ANQP "RX-ANQP " +#define RX_HS20_ANQP "RX-HS20-ANQP " +#define RX_HS20_ANQP_ICON "RX-HS20-ANQP-ICON " +#define RX_HS20_ICON "RX-HS20-ICON " + #define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION " #define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE " @@ -232,6 +253,7 @@ extern "C" { #define AP_STA_CONNECTED "AP-STA-CONNECTED " #define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED " #define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH " +#define AP_STA_POLL_OK "AP-STA-POLL-OK " #define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA " #define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA " @@ -254,9 +276,18 @@ extern "C" { #define AP_CSA_FINISHED "AP-CSA-FINISHED " +#define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED " +#define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON " + /* BSS Transition Management Response frame received */ #define BSS_TM_RESP "BSS-TM-RESP " +/* MBO IE with cellular data connection preference received */ +#define MBO_CELL_PREFERENCE "MBO-CELL-PREFERENCE " + +/* BSS Transition Management Request received with MBO transition reason */ +#define MBO_TRANSITION_REASON "MBO-TRANSITION-REASON " + /* BSS command information masks */ #define WPA_BSS_MASK_ALL 0xFFFDFFFF @@ -300,6 +331,7 @@ enum wpa_vendor_elem_frame { VENDOR_ELEM_P2P_ASSOC_REQ = 11, VENDOR_ELEM_P2P_ASSOC_RESP = 12, VENDOR_ELEM_ASSOC_REQ = 13, + VENDOR_ELEM_PROBE_REQ = 14, NUM_VENDOR_ELEM_FRAMES }; diff --git a/freebsd/contrib/wpa/src/crypto/aes-omac1.c b/freebsd/contrib/wpa/src/crypto/aes-omac1.c index 7e62ef85..8ad5a356 100644 --- a/freebsd/contrib/wpa/src/crypto/aes-omac1.c +++ b/freebsd/contrib/wpa/src/crypto/aes-omac1.c @@ -50,6 +50,9 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *pos, *end; size_t i, e, left, total_len; + if (TEST_FAIL()) + return -1; + ctx = aes_encrypt_init(key, key_len); if (ctx == NULL) return -1; diff --git a/freebsd/contrib/wpa/src/crypto/crypto.h b/freebsd/contrib/wpa/src/crypto/crypto.h index 534c4bd7..bdc3ba6f 100644 --- a/freebsd/contrib/wpa/src/crypto/crypto.h +++ b/freebsd/contrib/wpa/src/crypto/crypto.h @@ -80,6 +80,28 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); /** + * sha384_vector - SHA384 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac); + +/** + * sha512_vector - SHA512 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac); + +/** * des_encrypt - Encrypt one block with DES * @clear: 8 octets (in) * @key: 7 octets (in) (no parity bits included) @@ -135,7 +157,8 @@ void aes_decrypt_deinit(void *ctx); enum crypto_hash_alg { CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1, CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1, - CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256 + CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256, + CRYPTO_HASH_ALG_SHA384, CRYPTO_HASH_ALG_SHA512 }; struct crypto_hash; diff --git a/freebsd/contrib/wpa/src/crypto/crypto_openssl.c b/freebsd/contrib/wpa/src/crypto/crypto_openssl.c index 83630422..ee4d55eb 100644 --- a/freebsd/contrib/wpa/src/crypto/crypto_openssl.c +++ b/freebsd/contrib/wpa/src/crypto/crypto_openssl.c @@ -31,11 +31,61 @@ #include "sha1.h" #include "sha256.h" #include "sha384.h" +#include "md5.h" +#include "aes_wrap.h" #include "crypto.h" +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +/* Compatibility wrappers for older versions. */ + +static HMAC_CTX * HMAC_CTX_new(void) +{ + HMAC_CTX *ctx; + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx) + HMAC_CTX_init(ctx); + return ctx; +} + + +static void HMAC_CTX_free(HMAC_CTX *ctx) +{ + if (!ctx) + return; + HMAC_CTX_cleanup(ctx); + bin_clear_free(ctx, sizeof(*ctx)); +} + + +static EVP_MD_CTX * EVP_MD_CTX_new(void) +{ + EVP_MD_CTX *ctx; + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx) + EVP_MD_CTX_init(ctx); + return ctx; +} + + +static void EVP_MD_CTX_free(EVP_MD_CTX *ctx) +{ + if (!ctx) + return; + EVP_MD_CTX_cleanup(ctx); + bin_clear_free(ctx, sizeof(*ctx)); +} + +#endif /* OpenSSL version < 1.1.0 */ + static BIGNUM * get_group5_prime(void) { -#ifdef OPENSSL_IS_BORINGSSL +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + return BN_get_rfc3526_prime_1536(NULL); +#elif !defined(OPENSSL_IS_BORINGSSL) + return get_rfc3526_prime_1536(NULL); +#else static const unsigned char RFC3526_PRIME_1536[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, @@ -55,9 +105,7 @@ static BIGNUM * get_group5_prime(void) 0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, }; return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL); -#else /* OPENSSL_IS_BORINGSSL */ - return get_rfc3526_prime_1536(NULL); -#endif /* OPENSSL_IS_BORINGSSL */ +#endif } #ifdef OPENSSL_NO_SHA256 @@ -67,29 +115,38 @@ static BIGNUM * get_group5_prime(void) static int openssl_digest_vector(const EVP_MD *type, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { - EVP_MD_CTX ctx; + EVP_MD_CTX *ctx; size_t i; unsigned int mac_len; - EVP_MD_CTX_init(&ctx); - if (!EVP_DigestInit_ex(&ctx, type, NULL)) { + if (TEST_FAIL()) + return -1; + + ctx = EVP_MD_CTX_new(); + if (!ctx) + return -1; + if (!EVP_DigestInit_ex(ctx, type, NULL)) { wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s", ERR_error_string(ERR_get_error(), NULL)); + EVP_MD_CTX_free(ctx); return -1; } for (i = 0; i < num_elem; i++) { - if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) { + if (!EVP_DigestUpdate(ctx, addr[i], len[i])) { wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate " "failed: %s", ERR_error_string(ERR_get_error(), NULL)); + EVP_MD_CTX_free(ctx); return -1; } } - if (!EVP_DigestFinal(&ctx, mac, &mac_len)) { + if (!EVP_DigestFinal(ctx, mac, &mac_len)) { wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s", ERR_error_string(ERR_get_error(), NULL)); + EVP_MD_CTX_free(ctx); return -1; } + EVP_MD_CTX_free(ctx); return 0; } @@ -131,32 +188,34 @@ int rc4_skip(const u8 *key, size_t keylen, size_t skip, #ifdef OPENSSL_NO_RC4 return -1; #else /* OPENSSL_NO_RC4 */ - EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX *ctx; int outl; int res = -1; unsigned char skip_buf[16]; - EVP_CIPHER_CTX_init(&ctx); - if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) || - !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) || - !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) || - !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1)) + ctx = EVP_CIPHER_CTX_new(); + if (!ctx || + !EVP_CIPHER_CTX_set_padding(ctx, 0) || + !EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, NULL, NULL, 1) || + !EVP_CIPHER_CTX_set_key_length(ctx, keylen) || + !EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, 1)) goto out; while (skip >= sizeof(skip_buf)) { size_t len = skip; if (len > sizeof(skip_buf)) len = sizeof(skip_buf); - if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len)) + if (!EVP_CipherUpdate(ctx, skip_buf, &outl, skip_buf, len)) goto out; skip -= len; } - if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len)) + if (EVP_CipherUpdate(ctx, data, &outl, data, data_len)) res = 0; out: - EVP_CIPHER_CTX_cleanup(&ctx); + if (ctx) + EVP_CIPHER_CTX_free(ctx); return res; #endif /* OPENSSL_NO_RC4 */ } @@ -208,14 +267,16 @@ void * aes_encrypt_init(const u8 *key, size_t len) EVP_CIPHER_CTX *ctx; const EVP_CIPHER *type; + if (TEST_FAIL()) + return NULL; + type = aes_get_evp_cipher(len); if (type == NULL) return NULL; - ctx = os_malloc(sizeof(*ctx)); + ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return NULL; - EVP_CIPHER_CTX_init(ctx); if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) { os_free(ctx); return NULL; @@ -249,8 +310,7 @@ void aes_encrypt_deinit(void *ctx) wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d " "in AES encrypt", len); } - EVP_CIPHER_CTX_cleanup(c); - bin_clear_free(c, sizeof(*c)); + EVP_CIPHER_CTX_free(c); } @@ -259,16 +319,18 @@ void * aes_decrypt_init(const u8 *key, size_t len) EVP_CIPHER_CTX *ctx; const EVP_CIPHER *type; + if (TEST_FAIL()) + return NULL; + type = aes_get_evp_cipher(len); if (type == NULL) return NULL; - ctx = os_malloc(sizeof(*ctx)); + ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return NULL; - EVP_CIPHER_CTX_init(ctx); if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) { - os_free(ctx); + EVP_CIPHER_CTX_free(ctx); return NULL; } EVP_CIPHER_CTX_set_padding(ctx, 0); @@ -300,8 +362,7 @@ void aes_decrypt_deinit(void *ctx) wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d " "in AES decrypt", len); } - EVP_CIPHER_CTX_cleanup(c); - bin_clear_free(c, sizeof(*c)); + EVP_CIPHER_CTX_free(c); } @@ -340,51 +401,56 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) { - EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX *ctx; int clen, len; u8 buf[16]; + int res = -1; - EVP_CIPHER_CTX_init(&ctx); - if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) + if (TEST_FAIL()) return -1; - EVP_CIPHER_CTX_set_padding(&ctx, 0); - clen = data_len; - if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 || - clen != (int) data_len) + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) return -1; - + clen = data_len; len = sizeof(buf); - if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0) - return -1; - EVP_CIPHER_CTX_cleanup(&ctx); + if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 && + EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 && + EVP_EncryptUpdate(ctx, data, &clen, data, data_len) == 1 && + clen == (int) data_len && + EVP_EncryptFinal_ex(ctx, buf, &len) == 1 && len == 0) + res = 0; + EVP_CIPHER_CTX_free(ctx); - return 0; + return res; } int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) { - EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX *ctx; int plen, len; u8 buf[16]; + int res = -1; - EVP_CIPHER_CTX_init(&ctx); - if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) + if (TEST_FAIL()) return -1; - EVP_CIPHER_CTX_set_padding(&ctx, 0); - plen = data_len; - if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 || - plen != (int) data_len) + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) return -1; - + plen = data_len; len = sizeof(buf); - if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0) - return -1; - EVP_CIPHER_CTX_cleanup(&ctx); + if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 && + EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 && + EVP_DecryptUpdate(ctx, data, &plen, data, data_len) == 1 && + plen == (int) data_len && + EVP_DecryptFinal_ex(ctx, buf, &len) == 1 && len == 0) + res = 0; + EVP_CIPHER_CTX_free(ctx); + + return res; - return 0; } @@ -427,8 +493,8 @@ error: struct crypto_cipher { - EVP_CIPHER_CTX enc; - EVP_CIPHER_CTX dec; + EVP_CIPHER_CTX *enc; + EVP_CIPHER_CTX *dec; }; @@ -489,23 +555,25 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, return NULL; } - EVP_CIPHER_CTX_init(&ctx->enc); - EVP_CIPHER_CTX_set_padding(&ctx->enc, 0); - if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) || - !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) || - !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) { - EVP_CIPHER_CTX_cleanup(&ctx->enc); + if (!(ctx->enc = EVP_CIPHER_CTX_new()) || + !EVP_CIPHER_CTX_set_padding(ctx->enc, 0) || + !EVP_EncryptInit_ex(ctx->enc, cipher, NULL, NULL, NULL) || + !EVP_CIPHER_CTX_set_key_length(ctx->enc, key_len) || + !EVP_EncryptInit_ex(ctx->enc, NULL, NULL, key, iv)) { + if (ctx->enc) + EVP_CIPHER_CTX_free(ctx->enc); os_free(ctx); return NULL; } - EVP_CIPHER_CTX_init(&ctx->dec); - EVP_CIPHER_CTX_set_padding(&ctx->dec, 0); - if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) || - !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) || - !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) { - EVP_CIPHER_CTX_cleanup(&ctx->enc); - EVP_CIPHER_CTX_cleanup(&ctx->dec); + if (!(ctx->dec = EVP_CIPHER_CTX_new()) || + !EVP_CIPHER_CTX_set_padding(ctx->dec, 0) || + !EVP_DecryptInit_ex(ctx->dec, cipher, NULL, NULL, NULL) || + !EVP_CIPHER_CTX_set_key_length(ctx->dec, key_len) || + !EVP_DecryptInit_ex(ctx->dec, NULL, NULL, key, iv)) { + EVP_CIPHER_CTX_free(ctx->enc); + if (ctx->dec) + EVP_CIPHER_CTX_free(ctx->dec); os_free(ctx); return NULL; } @@ -518,7 +586,7 @@ int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len) { int outl; - if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len)) + if (!EVP_EncryptUpdate(ctx->enc, crypt, &outl, plain, len)) return -1; return 0; } @@ -529,7 +597,7 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, { int outl; outl = len; - if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len)) + if (!EVP_DecryptUpdate(ctx->dec, plain, &outl, crypt, len)) return -1; return 0; } @@ -537,19 +605,21 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, void crypto_cipher_deinit(struct crypto_cipher *ctx) { - EVP_CIPHER_CTX_cleanup(&ctx->enc); - EVP_CIPHER_CTX_cleanup(&ctx->dec); + EVP_CIPHER_CTX_free(ctx->enc); + EVP_CIPHER_CTX_free(ctx->dec); os_free(ctx); } void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L DH *dh; struct wpabuf *pubkey = NULL, *privkey = NULL; size_t publen, privlen; *priv = NULL; + wpabuf_free(*publ); *publ = NULL; dh = DH_new(); @@ -588,11 +658,63 @@ err: wpabuf_clear_free(privkey); DH_free(dh); return NULL; +#else + DH *dh; + struct wpabuf *pubkey = NULL, *privkey = NULL; + size_t publen, privlen; + BIGNUM *p = NULL, *g; + const BIGNUM *priv_key = NULL, *pub_key = NULL; + + *priv = NULL; + wpabuf_free(*publ); + *publ = NULL; + + dh = DH_new(); + if (dh == NULL) + return NULL; + + g = BN_new(); + p = get_group5_prime(); + if (!g || BN_set_word(g, 2) != 1 || !p || + DH_set0_pqg(dh, p, NULL, g) != 1) + goto err; + p = NULL; + g = NULL; + + if (DH_generate_key(dh) != 1) + goto err; + + DH_get0_key(dh, &pub_key, &priv_key); + publen = BN_num_bytes(pub_key); + pubkey = wpabuf_alloc(publen); + if (!pubkey) + goto err; + privlen = BN_num_bytes(priv_key); + privkey = wpabuf_alloc(privlen); + if (!privkey) + goto err; + + BN_bn2bin(pub_key, wpabuf_put(pubkey, publen)); + BN_bn2bin(priv_key, wpabuf_put(privkey, privlen)); + + *priv = privkey; + *publ = pubkey; + return dh; + +err: + BN_free(p); + BN_free(g); + wpabuf_clear_free(pubkey); + wpabuf_clear_free(privkey); + DH_free(dh); + return NULL; +#endif } void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L DH *dh; dh = DH_new(); @@ -623,6 +745,42 @@ void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ) err: DH_free(dh); return NULL; +#else + DH *dh; + BIGNUM *p = NULL, *g, *priv_key = NULL, *pub_key = NULL; + + dh = DH_new(); + if (dh == NULL) + return NULL; + + g = BN_new(); + p = get_group5_prime(); + if (!g || BN_set_word(g, 2) != 1 || !p || + DH_set0_pqg(dh, p, NULL, g) != 1) + goto err; + p = NULL; + g = NULL; + + priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL); + pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL); + if (!priv_key || !pub_key || DH_set0_key(dh, pub_key, priv_key) != 1) + goto err; + pub_key = NULL; + priv_key = NULL; + + if (DH_generate_key(dh) != 1) + goto err; + + return dh; + +err: + BN_free(p); + BN_free(g); + BN_free(pub_key); + BN_clear_free(priv_key); + DH_free(dh); + return NULL; +#endif } @@ -674,7 +832,7 @@ void dh5_free(void *ctx) struct crypto_hash { - HMAC_CTX ctx; + HMAC_CTX *ctx; }; @@ -709,16 +867,17 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; - HMAC_CTX_init(&ctx->ctx); + ctx->ctx = HMAC_CTX_new(); + if (!ctx->ctx) { + os_free(ctx); + return NULL; + } -#if OPENSSL_VERSION_NUMBER < 0x00909000 - HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL); -#else /* openssl < 0.9.9 */ - if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) { + if (HMAC_Init_ex(ctx->ctx, key, key_len, md, NULL) != 1) { + HMAC_CTX_free(ctx->ctx); bin_clear_free(ctx, sizeof(*ctx)); return NULL; } -#endif /* openssl < 0.9.9 */ return ctx; } @@ -728,7 +887,7 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) { if (ctx == NULL) return; - HMAC_Update(&ctx->ctx, data, len); + HMAC_Update(ctx->ctx, data, len); } @@ -741,18 +900,14 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) return -2; if (mac == NULL || len == NULL) { + HMAC_CTX_free(ctx->ctx); bin_clear_free(ctx, sizeof(*ctx)); return 0; } mdlen = *len; -#if OPENSSL_VERSION_NUMBER < 0x00909000 - HMAC_Final(&ctx->ctx, mac, &mdlen); - res = 1; -#else /* openssl < 0.9.9 */ - res = HMAC_Final(&ctx->ctx, mac, &mdlen); -#endif /* openssl < 0.9.9 */ - HMAC_CTX_cleanup(&ctx->ctx); + res = HMAC_Final(ctx->ctx, mac, &mdlen); + HMAC_CTX_free(ctx->ctx); bin_clear_free(ctx, sizeof(*ctx)); if (res == 1) { @@ -769,28 +924,26 @@ static int openssl_hmac_vector(const EVP_MD *type, const u8 *key, const u8 *addr[], const size_t *len, u8 *mac, unsigned int mdlen) { - HMAC_CTX ctx; + HMAC_CTX *ctx; size_t i; int res; - HMAC_CTX_init(&ctx); -#if OPENSSL_VERSION_NUMBER < 0x00909000 - HMAC_Init_ex(&ctx, key, key_len, type, NULL); -#else /* openssl < 0.9.9 */ - if (HMAC_Init_ex(&ctx, key, key_len, type, NULL) != 1) + if (TEST_FAIL()) return -1; -#endif /* openssl < 0.9.9 */ + + ctx = HMAC_CTX_new(); + if (!ctx) + return -1; + res = HMAC_Init_ex(ctx, key, key_len, type, NULL); + if (res != 1) + goto done; for (i = 0; i < num_elem; i++) - HMAC_Update(&ctx, addr[i], len[i]); + HMAC_Update(ctx, addr[i], len[i]); -#if OPENSSL_VERSION_NUMBER < 0x00909000 - HMAC_Final(&ctx, mac, &mdlen); - res = 1; -#else /* openssl < 0.9.9 */ - res = HMAC_Final(&ctx, mac, &mdlen); -#endif /* openssl < 0.9.9 */ - HMAC_CTX_cleanup(&ctx); + res = HMAC_Final(ctx, mac, &mdlen); +done: + HMAC_CTX_free(ctx); return res == 1 ? 0 : -1; } @@ -894,6 +1047,9 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, int ret = -1; size_t outlen, i; + if (TEST_FAIL()) + return -1; + ctx = CMAC_CTX_new(); if (ctx == NULL) return -1; @@ -943,13 +1099,20 @@ int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac) struct crypto_bignum * crypto_bignum_init(void) { + if (TEST_FAIL()) + return NULL; return (struct crypto_bignum *) BN_new(); } struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len) { - BIGNUM *bn = BN_bin2bn(buf, len, NULL); + BIGNUM *bn; + + if (TEST_FAIL()) + return NULL; + + bn = BN_bin2bn(buf, len, NULL); return (struct crypto_bignum *) bn; } @@ -968,6 +1131,9 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a, { int num_bytes, offset; + if (TEST_FAIL()) + return -1; + if (padlen > buflen) return -1; @@ -1021,6 +1187,9 @@ int crypto_bignum_exptmod(const struct crypto_bignum *a, int res; BN_CTX *bnctx; + if (TEST_FAIL()) + return -1; + bnctx = BN_CTX_new(); if (bnctx == NULL) return -1; @@ -1039,6 +1208,8 @@ int crypto_bignum_inverse(const struct crypto_bignum *a, BIGNUM *res; BN_CTX *bnctx; + if (TEST_FAIL()) + return -1; bnctx = BN_CTX_new(); if (bnctx == NULL) return -1; @@ -1054,6 +1225,8 @@ int crypto_bignum_sub(const struct crypto_bignum *a, const struct crypto_bignum *b, struct crypto_bignum *c) { + if (TEST_FAIL()) + return -1; return BN_sub((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ? 0 : -1; } @@ -1067,6 +1240,9 @@ int crypto_bignum_div(const struct crypto_bignum *a, BN_CTX *bnctx; + if (TEST_FAIL()) + return -1; + bnctx = BN_CTX_new(); if (bnctx == NULL) return -1; @@ -1087,6 +1263,9 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a, BN_CTX *bnctx; + if (TEST_FAIL()) + return -1; + bnctx = BN_CTX_new(); if (bnctx == NULL) return -1; @@ -1130,6 +1309,9 @@ int crypto_bignum_legendre(const struct crypto_bignum *a, BIGNUM *exp = NULL, *tmp = NULL; int res = -2; + if (TEST_FAIL()) + return -2; + bnctx = BN_CTX_new(); if (bnctx == NULL) return -2; @@ -1254,6 +1436,8 @@ void crypto_ec_deinit(struct crypto_ec *e) struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e) { + if (TEST_FAIL()) + return NULL; if (e == NULL) return NULL; return (struct crypto_ec_point *) EC_POINT_new(e->group); @@ -1300,6 +1484,9 @@ int crypto_ec_point_to_bin(struct crypto_ec *e, int ret = -1; int len = BN_num_bytes(e->prime); + if (TEST_FAIL()) + return -1; + x_bn = BN_new(); y_bn = BN_new(); @@ -1330,6 +1517,9 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e, EC_POINT *elem; int len = BN_num_bytes(e->prime); + if (TEST_FAIL()) + return NULL; + x = BN_bin2bn(val, len, NULL); y = BN_bin2bn(val + len, len, NULL); elem = EC_POINT_new(e->group); @@ -1357,6 +1547,8 @@ int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a, const struct crypto_ec_point *b, struct crypto_ec_point *c) { + if (TEST_FAIL()) + return -1; return EC_POINT_add(e->group, (EC_POINT *) c, (const EC_POINT *) a, (const EC_POINT *) b, e->bnctx) ? 0 : -1; } @@ -1366,6 +1558,8 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p, const struct crypto_bignum *b, struct crypto_ec_point *res) { + if (TEST_FAIL()) + return -1; return EC_POINT_mul(e->group, (EC_POINT *) res, NULL, (const EC_POINT *) p, (const BIGNUM *) b, e->bnctx) ? 0 : -1; @@ -1374,6 +1568,8 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p, int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p) { + if (TEST_FAIL()) + return -1; return EC_POINT_invert(e->group, (EC_POINT *) p, e->bnctx) ? 0 : -1; } @@ -1382,6 +1578,8 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e, struct crypto_ec_point *p, const struct crypto_bignum *x, int y_bit) { + if (TEST_FAIL()) + return -1; if (!EC_POINT_set_compressed_coordinates_GFp(e->group, (EC_POINT *) p, (const BIGNUM *) x, y_bit, e->bnctx) || @@ -1397,6 +1595,9 @@ crypto_ec_point_compute_y_sqr(struct crypto_ec *e, { BIGNUM *tmp, *tmp2, *y_sqr = NULL; + if (TEST_FAIL()) + return NULL; + tmp = BN_new(); tmp2 = BN_new(); diff --git a/freebsd/contrib/wpa/src/crypto/ms_funcs.c b/freebsd/contrib/wpa/src/crypto/ms_funcs.c index dda2ba7c..67e98dbf 100644 --- a/freebsd/contrib/wpa/src/crypto/ms_funcs.c +++ b/freebsd/contrib/wpa/src/crypto/ms_funcs.c @@ -50,7 +50,7 @@ static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len, WPA_PUT_LE16(ucs2_buffer + j, ((c & 0x1F) << 6) | (c2 & 0x3F)); j += 2; - } else if (i == utf8_string_len || + } else if (i == utf8_string_len - 1 || j >= ucs2_buffer_size - 1) { /* incomplete surrogate */ return -1; diff --git a/freebsd/contrib/wpa/src/crypto/sha256-internal.c b/freebsd/contrib/wpa/src/crypto/sha256-internal.c index c2ef3154..174bf3c4 100644 --- a/freebsd/contrib/wpa/src/crypto/sha256-internal.c +++ b/freebsd/contrib/wpa/src/crypto/sha256-internal.c @@ -30,6 +30,9 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, struct sha256_state ctx; size_t i; + if (TEST_FAIL()) + return -1; + sha256_init(&ctx); for (i = 0; i < num_elem; i++) if (sha256_process(&ctx, addr[i], len[i])) diff --git a/freebsd/contrib/wpa/src/crypto/sha256-prf.c b/freebsd/contrib/wpa/src/crypto/sha256-prf.c index 76496214..e2150e21 100644 --- a/freebsd/contrib/wpa/src/crypto/sha256-prf.c +++ b/freebsd/contrib/wpa/src/crypto/sha256-prf.c @@ -2,7 +2,7 @@ /* * SHA256-based PRF (IEEE 802.11r) - * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -24,14 +24,16 @@ * @data_len: Length of the data * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bytes of key to generate + * Returns: 0 on success, -1 on failure * * This function is used to derive new, cryptographically separate keys from a * given key. */ -void sha256_prf(const u8 *key, size_t key_len, const char *label, +int sha256_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len) { - sha256_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8); + return sha256_prf_bits(key, key_len, label, data, data_len, buf, + buf_len * 8); } @@ -44,15 +46,16 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label, * @data_len: Length of the data * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bits of key to generate + * Returns: 0 on success, -1 on failure * * This function is used to derive new, cryptographically separate keys from a * given key. If the requested buf_len is not divisible by eight, the least * significant 1-7 bits of the last octet in the output are not part of the * requested output. */ -void sha256_prf_bits(const u8 *key, size_t key_len, const char *label, - const u8 *data, size_t data_len, u8 *buf, - size_t buf_len_bits) +int sha256_prf_bits(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, + size_t buf_len_bits) { u16 counter = 1; size_t pos, plen; @@ -77,11 +80,14 @@ void sha256_prf_bits(const u8 *key, size_t key_len, const char *label, plen = buf_len - pos; WPA_PUT_LE16(counter_le, counter); if (plen >= SHA256_MAC_LEN) { - hmac_sha256_vector(key, key_len, 4, addr, len, - &buf[pos]); + if (hmac_sha256_vector(key, key_len, 4, addr, len, + &buf[pos]) < 0) + return -1; pos += SHA256_MAC_LEN; } else { - hmac_sha256_vector(key, key_len, 4, addr, len, hash); + if (hmac_sha256_vector(key, key_len, 4, addr, len, + hash) < 0) + return -1; os_memcpy(&buf[pos], hash, plen); pos += plen; break; @@ -99,4 +105,6 @@ void sha256_prf_bits(const u8 *key, size_t key_len, const char *label, } os_memset(hash, 0, sizeof(hash)); + + return 0; } diff --git a/freebsd/contrib/wpa/src/crypto/sha256.h b/freebsd/contrib/wpa/src/crypto/sha256.h index b15f5115..5219022e 100644 --- a/freebsd/contrib/wpa/src/crypto/sha256.h +++ b/freebsd/contrib/wpa/src/crypto/sha256.h @@ -1,6 +1,6 @@ /* * SHA256 hash implementation and interface functions - * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -15,11 +15,11 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac); -void sha256_prf(const u8 *key, size_t key_len, const char *label, - const u8 *data, size_t data_len, u8 *buf, size_t buf_len); -void sha256_prf_bits(const u8 *key, size_t key_len, const char *label, - const u8 *data, size_t data_len, u8 *buf, - size_t buf_len_bits); +int sha256_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len); +int sha256_prf_bits(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, + size_t buf_len_bits); void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label, const u8 *seed, size_t seed_len, u8 *out, size_t outlen); diff --git a/freebsd/contrib/wpa/src/crypto/tls.h b/freebsd/contrib/wpa/src/crypto/tls.h index 2e562339..11d504a9 100644 --- a/freebsd/contrib/wpa/src/crypto/tls.h +++ b/freebsd/contrib/wpa/src/crypto/tls.h @@ -95,6 +95,8 @@ struct tls_config { #define TLS_CONN_DISABLE_TLSv1_2 BIT(6) #define TLS_CONN_EAP_FAST BIT(7) #define TLS_CONN_DISABLE_TLSv1_0 BIT(8) +#define TLS_CONN_EXT_CERT_CHECK BIT(9) +#define TLS_CONN_REQUIRE_OCSP_ALL BIT(10) /** * struct tls_connection_params - Parameters for TLS connection @@ -139,6 +141,9 @@ struct tls_config { * @flags: Parameter options (TLS_CONN_*) * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response * or %NULL if OCSP is not enabled + * @ocsp_stapling_response_multi: DER encoded file with cached OCSP stapling + * response list (OCSPResponseList for ocsp_multi in RFC 6961) or %NULL if + * ocsp_multi is not enabled * * TLS connection parameters to be configured with tls_connection_set_params() * and tls_global_set_params(). @@ -179,6 +184,7 @@ struct tls_connection_params { unsigned int flags; const char *ocsp_stapling_response; + const char *ocsp_stapling_response_multi; }; @@ -330,29 +336,36 @@ int __must_check tls_connection_get_random(void *tls_ctx, struct tls_random *data); /** - * tls_connection_prf - Use TLS-PRF to derive keying material + * tls_connection_export_key - Derive keying material from a TLS connection * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @label: Label (e.g., description of the key) for PRF - * @server_random_first: seed is 0 = client_random|server_random, - * 1 = server_random|client_random - * @skip_keyblock: Skip TLS key block from the beginning of PRF output * @out: Buffer for output data from TLS-PRF * @out_len: Length of the output buffer * Returns: 0 on success, -1 on failure * - * tls_connection_prf() is required so that further keying material can be - * derived from the master secret. Example implementation of this function is in - * tls_prf_sha1_md5() when it is called with seed set to - * client_random|server_random (or server_random|client_random). For TLSv1.2 and - * newer, a different PRF is needed, though. + * Exports keying material using the mechanism described in RFC 5705. */ -int __must_check tls_connection_prf(void *tls_ctx, - struct tls_connection *conn, - const char *label, - int server_random_first, - int skip_keyblock, - u8 *out, size_t out_len); +int __must_check tls_connection_export_key(void *tls_ctx, + struct tls_connection *conn, + const char *label, + u8 *out, size_t out_len); + +/** + * tls_connection_get_eap_fast_key - Derive key material for EAP-FAST + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @out: Buffer for output data from TLS-PRF + * @out_len: Length of the output buffer + * Returns: 0 on success, -1 on failure + * + * Exports key material after the normal TLS key block for use with + * EAP-FAST. Most callers will want tls_connection_export_key(), but EAP-FAST + * uses a different legacy mechanism. + */ +int __must_check tls_connection_get_eap_fast_key(void *tls_ctx, + struct tls_connection *conn, + u8 *out, size_t out_len); /** * tls_connection_handshake - Process TLS handshake (client side) @@ -455,7 +468,9 @@ enum { TLS_CIPHER_RC4_SHA /* 0x0005 */, TLS_CIPHER_AES128_SHA /* 0x002f */, TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */, - TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */ + TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */, + TLS_CIPHER_RSA_DHE_AES256_SHA /* 0x0039 */, + TLS_CIPHER_AES256_SHA /* 0x0035 */, }; /** diff --git a/freebsd/contrib/wpa/src/crypto/tls_internal.c b/freebsd/contrib/wpa/src/crypto/tls_internal.c index 6a91f497..c6f65dc0 100644 --- a/freebsd/contrib/wpa/src/crypto/tls_internal.c +++ b/freebsd/contrib/wpa/src/crypto/tls_internal.c @@ -25,6 +25,11 @@ struct tls_global { int server; struct tlsv1_credentials *server_cred; int check_crl; + + void (*event_cb)(void *ctx, enum tls_event ev, + union tls_event_data *data); + void *cb_ctx; + int cert_in_cb; }; struct tls_connection { @@ -53,6 +58,11 @@ void * tls_init(const struct tls_config *conf) global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; + if (conf) { + global->event_cb = conf->event_cb; + global->cb_ctx = conf->cb_ctx; + global->cert_in_cb = conf->cert_in_cb; + } return global; } @@ -66,10 +76,12 @@ void tls_deinit(void *ssl_ctx) tlsv1_client_global_deinit(); #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER - tlsv1_cred_free(global->server_cred); tlsv1_server_global_deinit(); #endif /* CONFIG_TLS_INTERNAL_SERVER */ } +#ifdef CONFIG_TLS_INTERNAL_SERVER + tlsv1_cred_free(global->server_cred); +#endif /* CONFIG_TLS_INTERNAL_SERVER */ os_free(global); } @@ -97,6 +109,8 @@ struct tls_connection * tls_connection_init(void *tls_ctx) os_free(conn); return NULL; } + tlsv1_client_set_cb(conn->client, global->event_cb, + global->cb_ctx, global->cert_in_cb); } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER @@ -188,6 +202,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, if (conn->client == NULL) return -1; + if (params->flags & TLS_CONN_EXT_CERT_CHECK) { + wpa_printf(MSG_INFO, + "TLS: tls_ext_cert_check=1 not supported"); + return -1; + } + cred = tlsv1_cred_alloc(); if (cred == NULL) return -1; @@ -261,8 +281,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, return -1; } - tlsv1_client_set_time_checks( - conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS)); + tlsv1_client_set_flags(conn->client, params->flags); return 0; #else /* CONFIG_TLS_INTERNAL_CLIENT */ @@ -314,6 +333,13 @@ int tls_global_set_params(void *tls_ctx, return -1; } + if (params->ocsp_stapling_response) + cred->ocsp_stapling_response = + os_strdup(params->ocsp_stapling_response); + if (params->ocsp_stapling_response_multi) + cred->ocsp_stapling_response_multi = + os_strdup(params->ocsp_stapling_response_multi); + return 0; #else /* CONFIG_TLS_INTERNAL_SERVER */ return -1; @@ -370,9 +396,9 @@ static int tls_get_keyblock_size(struct tls_connection *conn) } -int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, - const char *label, int server_random_first, - int skip_keyblock, u8 *out, size_t out_len) +static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, + const char *label, int server_random_first, + int skip_keyblock, u8 *out, size_t out_len) { int ret = -1, skip = 0; u8 *tmp_out = NULL; @@ -392,14 +418,14 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, if (conn->client) { ret = tlsv1_client_prf(conn->client, label, server_random_first, - _out, out_len); + _out, skip + out_len); } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { ret = tlsv1_server_prf(conn->server, label, server_random_first, - _out, out_len); + _out, skip + out_len); } #endif /* CONFIG_TLS_INTERNAL_SERVER */ if (ret == 0 && skip_keyblock) @@ -410,6 +436,21 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } +int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, + const char *label, u8 *out, size_t out_len) +{ + return tls_connection_prf(tls_ctx, conn, label, 0, 0, out, out_len); +} + + +int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn, + u8 *out, size_t out_len) +{ + return tls_connection_prf(tls_ctx, conn, "key expansion", 1, 1, out, + out_len); +} + + struct wpabuf * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, @@ -623,7 +664,12 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, int tls_get_version(void *ssl_ctx, struct tls_connection *conn, char *buf, size_t buflen) { - /* TODO */ + if (conn == NULL) + return -1; +#ifdef CONFIG_TLS_INTERNAL_CLIENT + if (conn->client) + return tlsv1_client_get_version(conn->client, buf, buflen); +#endif /* CONFIG_TLS_INTERNAL_CLIENT */ return -1; } diff --git a/freebsd/contrib/wpa/src/drivers/driver.h b/freebsd/contrib/wpa/src/drivers/driver.h index 3cdab5a7..a449cc93 100644 --- a/freebsd/contrib/wpa/src/drivers/driver.h +++ b/freebsd/contrib/wpa/src/drivers/driver.h @@ -45,6 +45,22 @@ #define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000 #define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000 +#define HOSTAPD_CHAN_VHT_10_150 0x00100000 +#define HOSTAPD_CHAN_VHT_30_130 0x00200000 +#define HOSTAPD_CHAN_VHT_50_110 0x00400000 +#define HOSTAPD_CHAN_VHT_70_90 0x00800000 +#define HOSTAPD_CHAN_VHT_90_70 0x01000000 +#define HOSTAPD_CHAN_VHT_110_50 0x02000000 +#define HOSTAPD_CHAN_VHT_130_30 0x04000000 +#define HOSTAPD_CHAN_VHT_150_10 0x08000000 + +/* Filter gratuitous ARP */ +#define WPA_DATA_FRAME_FILTER_FLAG_ARP BIT(0) +/* Filter unsolicited Neighbor Advertisement */ +#define WPA_DATA_FRAME_FILTER_FLAG_NA BIT(1) +/* Filter unicast IP packets encrypted using the GTK */ +#define WPA_DATA_FRAME_FILTER_FLAG_GTK BIT(2) + /** * enum reg_change_initiator - Regulatory change initiator */ @@ -284,6 +300,18 @@ struct wpa_interface_info { #define WPAS_MAX_SCAN_SSIDS 16 /** + * struct wpa_driver_scan_ssid - SSIDs to scan for + * @ssid - specific SSID to scan for (ProbeReq) + * %NULL or zero-length SSID is used to indicate active scan + * with wildcard SSID. + * @ssid_len - Length of the SSID in octets + */ +struct wpa_driver_scan_ssid { + const u8 *ssid; + size_t ssid_len; +}; + +/** * struct wpa_driver_scan_params - Scan parameters * Data for struct wpa_driver_ops::scan2(). */ @@ -291,18 +319,7 @@ struct wpa_driver_scan_params { /** * ssids - SSIDs to scan for */ - struct wpa_driver_scan_ssid { - /** - * ssid - specific SSID to scan for (ProbeReq) - * %NULL or zero-length SSID is used to indicate active scan - * with wildcard SSID. - */ - const u8 *ssid; - /** - * ssid_len: Length of the SSID in octets - */ - size_t ssid_len; - } ssids[WPAS_MAX_SCAN_SSIDS]; + struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS]; /** * num_ssids - Number of entries in ssids array @@ -407,6 +424,37 @@ struct wpa_driver_scan_params { */ const u8 *mac_addr_mask; + /** + * sched_scan_plans - Scan plans for scheduled scan + * + * Each scan plan consists of the number of iterations to scan and the + * interval between scans. When a scan plan finishes (i.e., it was run + * for the specified number of iterations), the next scan plan is + * executed. The scan plans are executed in the order they appear in + * the array (lower index first). The last scan plan will run infinitely + * (until requested to stop), thus must not specify the number of + * iterations. All other scan plans must specify the number of + * iterations. + */ + struct sched_scan_plan { + u32 interval; /* In seconds */ + u32 iterations; /* Zero to run infinitely */ + } *sched_scan_plans; + + /** + * sched_scan_plans_num - Number of scan plans in sched_scan_plans array + */ + unsigned int sched_scan_plans_num; + + /** + * bssid - Specific BSSID to scan for + * + * This optional parameter can be used to replace the default wildcard + * BSSID with a specific BSSID to scan for if results are needed from + * only a single BSS. + */ + const u8 *bssid; + /* * NOTE: Whenever adding new parameters here, please make sure * wpa_scan_clone_params() and wpa_scan_free_params() get updated with @@ -828,6 +876,12 @@ struct wpa_driver_associate_params { * RRM (Radio Resource Measurements) */ int rrm_used; + + /** + * pbss - If set, connect to a PCP in a PBSS. Otherwise, connect to an + * AP as usual. Valid for DMG network only. + */ + int pbss; }; enum hide_ssid { @@ -1055,16 +1109,28 @@ struct wpa_driver_ap_params { * reenable - Whether this is to re-enable beaconing */ int reenable; + + /** + * pbss - Whether to start a PCP (in PBSS) instead of an AP in + * infrastructure BSS. Valid only for DMG network. + */ + int pbss; }; struct wpa_driver_mesh_bss_params { -#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001 +#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001 +#define WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT 0x00000002 +#define WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS 0x00000004 +#define WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE 0x00000008 /* * TODO: Other mesh configuration parameters would go here. * See NL80211_MESHCONF_* for all the mesh config parameters. */ unsigned int flags; + int auto_plinks; int peer_link_timeout; + int max_peer_links; + u16 ht_opmode; }; struct wpa_driver_mesh_join_params { @@ -1075,7 +1141,7 @@ struct wpa_driver_mesh_join_params { int ie_len; struct hostapd_freq_params freq; int beacon_int; - int max_peer_links; + int dtim_period; struct wpa_driver_mesh_bss_params conf; #define WPA_DRIVER_MESH_FLAG_USER_MPM 0x00000001 #define WPA_DRIVER_MESH_FLAG_DRIVER_MPM 0x00000002 @@ -1214,8 +1280,17 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL /** Driver supports automatic band selection */ #define WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY 0x0000004000000000ULL +/** Driver supports simultaneous off-channel operations */ +#define WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS 0x0000008000000000ULL +/** Driver supports full AP client state */ +#define WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE 0x0000010000000000ULL +/** Driver supports P2P Listen offload */ +#define WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD 0x0000020000000000ULL u64 flags; +#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \ + (drv_flags & WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE) + #define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001 #define WPA_DRIVER_SMPS_MODE_DYNAMIC 0x00000002 unsigned int smps_modes; @@ -1231,6 +1306,15 @@ struct wpa_driver_capa { /** Maximum number of supported active probe SSIDs for sched_scan */ int max_sched_scan_ssids; + /** Maximum number of supported scan plans for scheduled scan */ + unsigned int max_sched_scan_plans; + + /** Maximum interval in a scan plan. In seconds */ + u32 max_sched_scan_plan_interval; + + /** Maximum number of iterations in a single scan plan */ + u32 max_sched_scan_plan_iterations; + /** Whether sched_scan (offloaded scanning) is supported */ int sched_scan_supported; @@ -1296,6 +1380,12 @@ struct wpa_driver_capa { * offset, namely the 6th byte in the Action frame body. */ #define WPA_DRIVER_FLAGS_TX_POWER_INSERTION 0x00000008 +/** + * Driver supports RRM. With this support, the driver will accept to use RRM in + * (Re)Association Request frames, without supporting quiet period. + */ +#define WPA_DRIVER_FLAGS_SUPPORT_RRM 0x00000010 + u32 rrm_flags; /* Driver concurrency capabilities */ @@ -1304,13 +1394,18 @@ struct wpa_driver_capa { unsigned int max_conc_chan_2_4; /* Maximum number of concurrent channels on 5 GHz */ unsigned int max_conc_chan_5_0; + + /* Maximum number of supported CSA counters */ + u16 max_csa_counters; }; struct hostapd_data; struct hostap_sta_driver_data { - unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes; + unsigned long rx_packets, tx_packets; + unsigned long long rx_bytes, tx_bytes; + int bytes_64bit; /* whether 64-bit byte counters are supported */ unsigned long current_tx_rate; unsigned long inactive_msec; unsigned long flags; @@ -1336,6 +1431,7 @@ struct hostapd_sta_add_params { u32 flags_mask; /* unset bits in flags */ #ifdef CONFIG_MESH enum mesh_plink_state plink_state; + u16 peer_aid; #endif /* CONFIG_MESH */ int set; /* Set STA parameters instead of add */ u8 qosinfo; @@ -1345,6 +1441,7 @@ struct hostapd_sta_add_params { size_t supp_channels_len; const u8 *supp_oper_classes; size_t supp_oper_classes_len; + int support_p2p_ps; }; struct mac_address { @@ -1450,6 +1547,7 @@ struct wpa_bss_params { #define WPA_STA_MFP BIT(3) #define WPA_STA_TDLS_PEER BIT(4) #define WPA_STA_AUTHENTICATED BIT(5) +#define WPA_STA_ASSOCIATED BIT(6) enum tdls_oper { TDLS_DISCOVERY_REQ, @@ -1554,8 +1652,8 @@ struct csa_settings { struct beacon_data beacon_csa; struct beacon_data beacon_after; - u16 counter_offset_beacon; - u16 counter_offset_presp; + u16 counter_offset_beacon[2]; + u16 counter_offset_presp[2]; }; /* TDLS peer capabilities for send_tdls_mgmt() */ @@ -1883,6 +1981,14 @@ struct wpa_driver_ops { void (*poll)(void *priv); /** + * get_ifindex - Get interface index + * @priv: private driver interface data + * + * Returns: Interface index + */ + unsigned int (*get_ifindex)(void *priv); + + /** * get_ifname - Get interface name * @priv: private driver interface data * @@ -1960,10 +2066,13 @@ struct wpa_driver_ops { * @noack: Do not wait for this frame to be acked (disable retries) * @freq: Frequency (in MHz) to send the frame on, or 0 to let the * driver decide + * @csa_offs: Array of CSA offsets or %NULL + * @csa_offs_len: Number of elements in csa_offs * Returns: 0 on success, -1 on failure */ int (*send_mlme)(void *priv, const u8 *data, size_t data_len, - int noack, unsigned int freq); + int noack, unsigned int freq, const u16 *csa_offs, + size_t csa_offs_len); /** * update_ft_ies - Update FT (IEEE 802.11r) IEs @@ -2013,6 +2122,7 @@ struct wpa_driver_ops { /** * global_init - Global driver initialization + * @ctx: wpa_global pointer * Returns: Pointer to private data (global), %NULL on failure * * This optional function is called to initialize the driver wrapper @@ -2022,7 +2132,7 @@ struct wpa_driver_ops { * use init2() function instead of init() to get the pointer to global * data available to per-interface initializer. */ - void * (*global_init)(void); + void * (*global_init)(void *ctx); /** * global_deinit - Global driver deinitialization @@ -2308,12 +2418,17 @@ struct wpa_driver_ops { * @params: Station parameters * Returns: 0 on success, -1 on failure * - * This function is used to add a station entry to the driver once the - * station has completed association. This is only used if the driver + * This function is used to add or set (params->set 1) a station + * entry in the driver. Adding STA entries is used only if the driver * does not take care of association processing. * - * With TDLS, this function is also used to add or set (params->set 1) - * TDLS peer entries. + * With drivers that don't support full AP client state, this function + * is used to add a station entry to the driver once the station has + * completed association. + * + * With TDLS, this function is used to add or set (params->set 1) + * TDLS peer entries (even with drivers that do not support full AP + * client state). */ int (*sta_add)(void *priv, struct hostapd_sta_add_params *params); @@ -2399,12 +2514,13 @@ struct wpa_driver_ops { * change interface address) * @bridge: Bridge interface to use or %NULL if no bridge configured * @use_existing: Whether to allow existing interface to be used + * @setup_ap: Whether to setup AP for %WPA_IF_AP_BSS interfaces * Returns: 0 on success, -1 on failure */ int (*if_add)(void *priv, enum wpa_driver_if_type type, const char *ifname, const u8 *addr, void *bss_ctx, void **drv_priv, char *force_ifname, u8 *if_addr, - const char *bridge, int use_existing); + const char *bridge, int use_existing, int setup_ap); /** * if_remove - Remove a virtual interface @@ -2986,7 +3102,6 @@ struct wpa_driver_ops { * sched_scan - Request the driver to initiate scheduled scan * @priv: Private driver interface data * @params: Scan parameters - * @interval: Interval between scan cycles in milliseconds * Returns: 0 on success, -1 on failure * * This operation should be used for scheduled scan offload to @@ -2997,8 +3112,7 @@ struct wpa_driver_ops { * and if not provided or if it returns -1, we fall back to * normal host-scheduled scans. */ - int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params, - u32 interval); + int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params); /** * stop_sched_scan - Request the driver to stop a scheduled scan @@ -3203,11 +3317,9 @@ struct wpa_driver_ops { * set_current_cipher_suite - Set current cipher suite * @priv: Private driver interface data * @cs: EUI64 identifier - * @cs_len: Length of the cs buffer in octets * Returns: 0 on success, -1 on failure (or if not supported) */ - int (*set_current_cipher_suite)(void *priv, const u8 *cs, - size_t cs_len); + int (*set_current_cipher_suite)(void *priv, u64 cs); /** * enable_controlled_port - Set controlled port status @@ -3439,6 +3551,78 @@ struct wpa_driver_ops { * on. Local device is assuming P2P Client role. */ int (*set_prob_oper_freq)(void *priv, unsigned int freq); + + /** + * abort_scan - Request the driver to abort an ongoing scan + * @priv: Private driver interface data + * Returns 0 on success, -1 on failure + */ + int (*abort_scan)(void *priv); + + /** + * configure_data_frame_filters - Request to configure frame filters + * @priv: Private driver interface data + * @filter_flags: The type of frames to filter (bitfield of + * WPA_DATA_FRAME_FILTER_FLAG_*) + * Returns: 0 on success or -1 on failure + */ + int (*configure_data_frame_filters)(void *priv, u32 filter_flags); + + /** + * get_ext_capab - Get extended capabilities for the specified interface + * @priv: Private driver interface data + * @type: Interface type for which to get extended capabilities + * @ext_capab: Extended capabilities fetched + * @ext_capab_mask: Extended capabilities mask + * @ext_capab_len: Length of the extended capabilities + * Returns: 0 on success or -1 on failure + */ + int (*get_ext_capab)(void *priv, enum wpa_driver_if_type type, + const u8 **ext_capab, const u8 **ext_capab_mask, + unsigned int *ext_capab_len); + + /** + * p2p_lo_start - Start offloading P2P listen to device + * @priv: Private driver interface data + * @freq: Listening frequency (MHz) for P2P listen + * @period: Length of the listen operation in milliseconds + * @interval: Interval for running the listen operation in milliseconds + * @count: Number of times to run the listen operation + * @device_types: Device primary and secondary types + * @dev_types_len: Number of bytes for device_types + * @ies: P2P IE and WSC IE for Probe Response frames + * @ies_len: Length of ies in bytes + * Returns: 0 on success or -1 on failure + */ + int (*p2p_lo_start)(void *priv, unsigned int freq, + unsigned int period, unsigned int interval, + unsigned int count, + const u8 *device_types, size_t dev_types_len, + const u8 *ies, size_t ies_len); + + /** + * p2p_lo_stop - Stop P2P listen offload + * @priv: Private driver interface data + * Returns: 0 on success or -1 on failure + */ + int (*p2p_lo_stop)(void *priv); + + /** + * set_default_scan_ies - Set default scan IEs + * @priv: Private driver interface data + * @ies: Scan default IEs buffer + * @ies_len: Length of IEs in bytes + * Returns: 0 on success or -1 on failure + * + * The driver can use these by default when there are no scan IEs coming + * in the subsequent scan requests. Also in case of one or more of IEs + * given in set_default_scan_ies() are missing in the subsequent scan + * request, the driver should merge the missing scan IEs in the scan + * request from the IEs set by set_default_scan_ies() in the Probe + * Request frames sent. + */ + int (*set_default_scan_ies)(void *priv, const u8 *ies, size_t ies_len); + }; @@ -3923,6 +4107,11 @@ enum wpa_event_type { * on a DFS frequency by a driver that supports DFS Offload. */ EVENT_DFS_CAC_STARTED, + + /** + * EVENT_P2P_LO_STOP - Notify that P2P listen offload is stopped + */ + EVENT_P2P_LO_STOP, }; @@ -4098,6 +4287,12 @@ union wpa_event_data { * ptk_kek_len - The length of ptk_kek */ size_t ptk_kek_len; + + /** + * subnet_status - The subnet status: + * 0 = unknown, 1 = unchanged, 2 = changed + */ + u8 subnet_status; } assoc_info; /** @@ -4174,6 +4369,7 @@ union wpa_event_data { * struct interface_status - Data for EVENT_INTERFACE_STATUS */ struct interface_status { + unsigned int ifindex; char ifname[100]; enum { EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED @@ -4301,6 +4497,12 @@ union wpa_event_data { * status_code - Status Code from (Re)association Response */ u16 status_code; + + /** + * timed_out - Whether failure is due to timeout (etc.) rather + * than explicit rejection response from the AP. + */ + int timed_out; } assoc_reject; struct timeout_event { @@ -4381,6 +4583,9 @@ union wpa_event_data { * @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard * SSID) * @num_ssids: Number of entries in ssids array + * @external_scan: Whether the scan info is for an external scan + * @nl_scan_event: 1 if the source of this scan event is a normal scan, + * 0 if the source of the scan event is a vendor scan */ struct scan_info { int aborted; @@ -4388,6 +4593,8 @@ union wpa_event_data { size_t num_freqs; struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS]; size_t num_ssids; + int external_scan; + int nl_scan_event; } scan_info; /** @@ -4630,6 +4837,27 @@ union wpa_event_data { u16 ch_width; enum hostapd_hw_mode hw_mode; } acs_selected_channels; + + /** + * struct p2p_lo_stop - Reason code for P2P Listen offload stop event + * @reason_code: Reason for stopping offload + * P2P_LO_STOPPED_REASON_COMPLETE: Listen offload finished as + * scheduled. + * P2P_LO_STOPPED_REASON_RECV_STOP_CMD: Host requested offload to + * be stopped. + * P2P_LO_STOPPED_REASON_INVALID_PARAM: Invalid listen offload + * parameters. + * P2P_LO_STOPPED_REASON_NOT_SUPPORTED: Listen offload not + * supported by device. + */ + struct p2p_lo_stop { + enum { + P2P_LO_STOPPED_REASON_COMPLETE = 0, + P2P_LO_STOPPED_REASON_RECV_STOP_CMD, + P2P_LO_STOPPED_REASON_INVALID_PARAM, + P2P_LO_STOPPED_REASON_NOT_SUPPORTED, + } reason_code; + } p2p_lo_stop; }; /** @@ -4645,6 +4873,18 @@ union wpa_event_data { void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data); +/** + * wpa_supplicant_event_global - Report a driver event for wpa_supplicant + * @ctx: Context pointer (wpa_s); this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @event: event type (defined above) + * @data: possible extra data for the event + * + * Same as wpa_supplicant_event(), but we search for the interface in + * wpa_global. + */ +void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, + union wpa_event_data *data); /* * The following inline functions are provided for convenience to simplify @@ -4697,8 +4937,52 @@ int vht_supported(const struct hostapd_hw_modes *mode); struct wowlan_triggers * wpa_get_wowlan_triggers(const char *wowlan_triggers, const struct wpa_driver_capa *capa); +/* Convert driver flag to string */ +const char * driver_flag_to_string(u64 flag); /* NULL terminated array of linked in driver wrappers */ extern const struct wpa_driver_ops *const wpa_drivers[]; + +/* Available drivers */ + +#ifdef CONFIG_DRIVER_WEXT +extern const struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ +#endif /* CONFIG_DRIVER_WEXT */ +#ifdef CONFIG_DRIVER_NL80211 +/* driver_nl80211.c */ +extern const struct wpa_driver_ops wpa_driver_nl80211_ops; +#endif /* CONFIG_DRIVER_NL80211 */ +#ifdef CONFIG_DRIVER_HOSTAP +extern const struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ +#endif /* CONFIG_DRIVER_HOSTAP */ +#ifdef CONFIG_DRIVER_BSD +extern const struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ +#endif /* CONFIG_DRIVER_BSD */ +#ifdef CONFIG_DRIVER_OPENBSD +/* driver_openbsd.c */ +extern const struct wpa_driver_ops wpa_driver_openbsd_ops; +#endif /* CONFIG_DRIVER_OPENBSD */ +#ifdef CONFIG_DRIVER_NDIS +extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */ +#endif /* CONFIG_DRIVER_NDIS */ +#ifdef CONFIG_DRIVER_WIRED +extern const struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */ +#endif /* CONFIG_DRIVER_WIRED */ +#ifdef CONFIG_DRIVER_MACSEC_QCA +/* driver_macsec_qca.c */ +extern const struct wpa_driver_ops wpa_driver_macsec_qca_ops; +#endif /* CONFIG_DRIVER_MACSEC_QCA */ +#ifdef CONFIG_DRIVER_ROBOSWITCH +/* driver_roboswitch.c */ +extern const struct wpa_driver_ops wpa_driver_roboswitch_ops; +#endif /* CONFIG_DRIVER_ROBOSWITCH */ +#ifdef CONFIG_DRIVER_ATHEROS +/* driver_atheros.c */ +extern const struct wpa_driver_ops wpa_driver_atheros_ops; +#endif /* CONFIG_DRIVER_ATHEROS */ +#ifdef CONFIG_DRIVER_NONE +extern const struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ +#endif /* CONFIG_DRIVER_NONE */ + #endif /* DRIVER_H */ diff --git a/freebsd/contrib/wpa/src/drivers/driver_bsd.c b/freebsd/contrib/wpa/src/drivers/driver_bsd.c index 5f6e129d..c1679806 100644 --- a/freebsd/contrib/wpa/src/drivers/driver_bsd.c +++ b/freebsd/contrib/wpa/src/drivers/driver_bsd.c @@ -49,14 +49,25 @@ #include "l2_packet/l2_packet.h" +struct bsd_driver_global { + void *ctx; + int sock; /* socket for 802.11 ioctls */ + int route; /* routing socket for events */ + char *event_buf; + size_t event_buf_len; + struct dl_list ifaces; /* list of interfaces */ +}; + struct bsd_driver_data { + struct dl_list list; + struct bsd_driver_global *global; struct hostapd_data *hapd; /* back pointer */ - int sock; /* open socket for 802.11 ioctls */ struct l2_packet_data *sock_xmit;/* raw packet xmit socket */ - int route; /* routing socket for events */ char ifname[IFNAMSIZ+1]; /* interface name */ + int flags; unsigned int ifindex; /* interface index */ + int if_removed; /* has the interface been removed? */ void *ctx; struct wpa_driver_capa capa; /* driver capability */ int is_ap; /* Access point mode */ @@ -64,17 +75,46 @@ struct bsd_driver_data { int prev_privacy; /* privacy state to restore on deinit */ int prev_wpa; /* wpa state to restore on deinit */ enum ieee80211_opmode opmode; /* operation mode */ - char *event_buf; - size_t event_buf_len; }; /* Generic functions for hostapd and wpa_supplicant */ +static struct bsd_driver_data * +bsd_get_drvindex(void *priv, unsigned int ifindex) +{ + struct bsd_driver_global *global = priv; + struct bsd_driver_data *drv; + + dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) { + if (drv->ifindex == ifindex) + return drv; + } + return NULL; +} + +#ifndef HOSTAPD +static struct bsd_driver_data * +bsd_get_drvname(void *priv, const char *ifname) +{ + struct bsd_driver_global *global = priv; + struct bsd_driver_data *drv; + + dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) { + if (os_strcmp(drv->ifname, ifname) == 0) + return drv; + } + return NULL; +} +#endif /* HOSTAPD */ + static int bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) { struct bsd_driver_data *drv = priv; struct ieee80211req ireq; + if (drv->ifindex == 0 || drv->if_removed) + return -1; + os_memset(&ireq, 0, sizeof(ireq)); os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name)); ireq.i_type = op; @@ -82,7 +122,7 @@ bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) ireq.i_data = (void *) arg; ireq.i_len = arg_len; - if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) { + if (ioctl(drv->global->sock, SIOCS80211, &ireq) < 0) { wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, " "arg_len=%u]: %s", op, val, arg_len, strerror(errno)); @@ -103,7 +143,7 @@ bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg, ireq->i_len = arg_len; ireq->i_data = arg; - if (ioctl(drv->sock, SIOCG80211, ireq) < 0) { + if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) { wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, " "arg_len=%u]: %s", op, arg_len, strerror(errno)); return -1; @@ -144,7 +184,7 @@ bsd_get_ssid(void *priv, u8 *ssid, int len) os_memset(&ifr, 0, sizeof(ifr)); os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ifr.ifr_data = (void *)&nwid; - if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 || + if (ioctl(drv->global->sock, SIOCG80211NWID, &ifr) < 0 || nwid.i_len > IEEE80211_NWID_LEN) return -1; os_memcpy(ssid, nwid.i_nwid, nwid.i_len); @@ -167,7 +207,7 @@ bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len) os_memset(&ifr, 0, sizeof(ifr)); os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ifr.ifr_data = (void *)&nwid; - return ioctl(drv->sock, SIOCS80211NWID, &ifr); + return ioctl(drv->global->sock, SIOCS80211NWID, &ifr); #else return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len); #endif @@ -182,7 +222,7 @@ bsd_get_if_media(void *priv) os_memset(&ifmr, 0, sizeof(ifmr)); os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); - if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) { + if (ioctl(drv->global->sock, SIOCGIFMEDIA, &ifmr) < 0) { wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__, strerror(errno)); return -1; @@ -201,7 +241,7 @@ bsd_set_if_media(void *priv, int media) os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ifr.ifr_media = media; - if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) { + if (ioctl(drv->global->sock, SIOCSIFMEDIA, &ifr) < 0) { wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__, strerror(errno)); return -1; @@ -264,11 +304,12 @@ bsd_ctrl_iface(void *priv, int enable) os_memset(&ifr, 0, sizeof(ifr)); os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) { + if (ioctl(drv->global->sock, SIOCGIFFLAGS, &ifr) < 0) { wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s", strerror(errno)); return -1; } + drv->flags = ifr.ifr_flags; if (enable) { if (ifr.ifr_flags & IFF_UP) @@ -280,12 +321,13 @@ bsd_ctrl_iface(void *priv, int enable) ifr.ifr_flags &= ~IFF_UP; } - if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) { + if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) { wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s", strerror(errno)); return -1; } + drv->flags = ifr.ifr_flags; return 0; } @@ -577,7 +619,7 @@ bsd_set_freq(void *priv, struct hostapd_freq_params *freq) os_memset(&creq, 0, sizeof(creq)); os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name)); creq.i_channel = (u_int16_t)channel; - return ioctl(drv->sock, SIOCS80211CHANNEL, &creq); + return ioctl(drv->global->sock, SIOCS80211CHANNEL, &creq); #else /* SIOCS80211CHANNEL */ return set80211param(priv, IEEE80211_IOC_CHANNEL, channel); #endif /* SIOCS80211CHANNEL */ @@ -731,7 +773,8 @@ bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, static void bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) { - struct bsd_driver_data *drv = ctx; + struct bsd_driver_global *global = sock_ctx; + struct bsd_driver_data *drv; struct if_announcemsghdr *ifan; struct rt_msghdr *rtm; struct ieee80211_michael_event *mic; @@ -740,7 +783,7 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) int n; union wpa_event_data data; - n = read(sock, drv->event_buf, drv->event_buf_len); + n = read(sock, global->event_buf, global->event_buf_len); if (n < 0) { if (errno != EINTR && errno != EAGAIN) wpa_printf(MSG_ERROR, "%s read() failed: %s", @@ -748,15 +791,18 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) return; } - rtm = (struct rt_msghdr *) drv->event_buf; + rtm = (struct rt_msghdr *) global->event_buf; if (rtm->rtm_version != RTM_VERSION) { wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", rtm->rtm_version); return; } - ifan = (struct if_announcemsghdr *) rtm; switch (rtm->rtm_type) { case RTM_IEEE80211: + ifan = (struct if_announcemsghdr *) rtm; + drv = bsd_get_drvindex(global, ifan->ifan_index); + if (drv == NULL) + return; switch (ifan->ifan_what) { case RTM_IEEE80211_ASSOC: case RTM_IEEE80211_REASSOC: @@ -812,21 +858,15 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) return NULL; } - drv->event_buf_len = rtbuf_len(); - - drv->event_buf = os_malloc(drv->event_buf_len); - if (drv->event_buf == NULL) { - wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); + drv->ifindex = if_nametoindex(params->ifname); + if (drv->ifindex == 0) { + wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", + __func__, params->ifname); goto bad; } drv->hapd = hapd; - drv->sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->sock < 0) { - wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", - strerror(errno)); - goto bad; - } + drv->global = params->global_priv; os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, @@ -840,28 +880,18 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) if (bsd_ctrl_iface(drv, 0) < 0) goto bad; - drv->route = socket(PF_ROUTE, SOCK_RAW, 0); - if (drv->route < 0) { - wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s", - strerror(errno)); - goto bad; - } - eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv, - NULL); - if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) { wpa_printf(MSG_ERROR, "%s: failed to set operation mode", __func__); goto bad; } + dl_list_add(&drv->global->ifaces, &drv->list); + return drv; bad: if (drv->sock_xmit != NULL) l2_packet_deinit(drv->sock_xmit); - if (drv->sock >= 0) - close(drv->sock); - os_free(drv->event_buf); os_free(drv); return NULL; } @@ -872,16 +902,10 @@ bsd_deinit(void *priv) { struct bsd_driver_data *drv = priv; - if (drv->route >= 0) { - eloop_unregister_read_sock(drv->route); - close(drv->route); - } - bsd_ctrl_iface(drv, 0); - if (drv->sock >= 0) - close(drv->sock); + if (drv->ifindex != 0) + bsd_ctrl_iface(drv, 0); if (drv->sock_xmit != NULL) l2_packet_deinit(drv->sock_xmit); - os_free(drv->event_buf); os_free(drv); } @@ -933,7 +957,7 @@ wpa_driver_bsd_get_bssid(void *priv, u8 *bssid) struct ieee80211_bssid bs; os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name)); - if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0) + if (ioctl(drv->global->sock, SIOCG80211BSSID, &bs) < 0) return -1; os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid)); return 0; @@ -967,7 +991,7 @@ wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy) int ret = 0; wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d", - __FUNCTION__, wpa, privacy); + __func__, wpa, privacy); if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0) ret = -1; @@ -982,7 +1006,7 @@ wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy) static int wpa_driver_bsd_set_wpa(void *priv, int enabled) { - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); + wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled); } @@ -1201,7 +1225,8 @@ wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) static void wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) { - struct bsd_driver_data *drv = sock_ctx; + struct bsd_driver_global *global = sock_ctx; + struct bsd_driver_data *drv; struct if_announcemsghdr *ifan; struct if_msghdr *ifm; struct rt_msghdr *rtm; @@ -1211,7 +1236,12 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) struct ieee80211_join_event *join; int n; - n = read(sock, drv->event_buf, drv->event_buf_len); + /* + * CID 1394785: Memory - illegal access (STRING_NULL): + * Though global->event_buf is a char *, it actually contains + * a struct rt_msghdr *. See below. + */ + n = read(sock, global->event_buf, global->event_buf_len); if (n < 0) { if (errno != EINTR && errno != EAGAIN) wpa_printf(MSG_ERROR, "%s read() failed: %s", @@ -1219,7 +1249,11 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) return; } - rtm = (struct rt_msghdr *) drv->event_buf; + /* + * CID 1394785: global->event_buf is assigned here to a + * struct rt_msghdr *. + */ + rtm = (struct rt_msghdr *) global->event_buf; if (rtm->rtm_version != RTM_VERSION) { wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", rtm->rtm_version); @@ -1229,53 +1263,79 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) switch (rtm->rtm_type) { case RTM_IFANNOUNCE: ifan = (struct if_announcemsghdr *) rtm; - if (ifan->ifan_index != drv->ifindex) - break; - os_strlcpy(event.interface_status.ifname, drv->ifname, - sizeof(event.interface_status.ifname)); switch (ifan->ifan_what) { case IFAN_DEPARTURE: + drv = bsd_get_drvindex(global, ifan->ifan_index); + if (drv) + drv->if_removed = 1; event.interface_status.ievent = EVENT_INTERFACE_REMOVED; + break; + case IFAN_ARRIVAL: + drv = bsd_get_drvname(global, ifan->ifan_name); + if (drv) { + drv->ifindex = ifan->ifan_index; + drv->if_removed = 0; + } + event.interface_status.ievent = EVENT_INTERFACE_ADDED; + break; default: + wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action"); return; } wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", - event.interface_status.ifname, + ifan->ifan_name, ifan->ifan_what == IFAN_DEPARTURE ? "removed" : "added"); - wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); + os_strlcpy(event.interface_status.ifname, ifan->ifan_name, + sizeof(event.interface_status.ifname)); + if (drv) { + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, + &event); + /* + * Set ifindex to zero after sending the event as the + * event might query the driver to ensure a match. + */ + if (ifan->ifan_what == IFAN_DEPARTURE) + drv->ifindex = 0; + } else { + wpa_supplicant_event_global(global->ctx, + EVENT_INTERFACE_STATUS, + &event); + } break; case RTM_IEEE80211: ifan = (struct if_announcemsghdr *) rtm; - if (ifan->ifan_index != drv->ifindex) - break; + drv = bsd_get_drvindex(global, ifan->ifan_index); + if (drv == NULL) + return; switch (ifan->ifan_what) { case RTM_IEEE80211_ASSOC: case RTM_IEEE80211_REASSOC: if (drv->is_ap) break; - wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); break; case RTM_IEEE80211_DISASSOC: if (drv->is_ap) break; - wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); break; case RTM_IEEE80211_SCAN: if (drv->is_ap) break; - wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); + wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, + NULL); break; case RTM_IEEE80211_LEAVE: leave = (struct ieee80211_leave_event *) &ifan[1]; - drv_event_disassoc(ctx, leave->iev_addr); + drv_event_disassoc(drv->ctx, leave->iev_addr); break; case RTM_IEEE80211_JOIN: #ifdef RTM_IEEE80211_REJOIN case RTM_IEEE80211_REJOIN: #endif join = (struct ieee80211_join_event *) &ifan[1]; - bsd_new_sta(drv, ctx, join->iev_addr); + bsd_new_sta(drv, drv->ctx, join->iev_addr); break; case RTM_IEEE80211_REPLAY: /* ignore */ @@ -1290,23 +1350,30 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) os_memset(&event, 0, sizeof(event)); event.michael_mic_failure.unicast = !IEEE80211_IS_MULTICAST(mic->iev_dst); - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, - &event); + wpa_supplicant_event(drv->ctx, + EVENT_MICHAEL_MIC_FAILURE, &event); break; } break; case RTM_IFINFO: ifm = (struct if_msghdr *) rtm; - if (ifm->ifm_index != drv->ifindex) - break; - if ((rtm->rtm_flags & RTF_UP) == 0) { - os_strlcpy(event.interface_status.ifname, drv->ifname, - sizeof(event.interface_status.ifname)); - event.interface_status.ievent = EVENT_INTERFACE_REMOVED; + drv = bsd_get_drvindex(global, ifm->ifm_index); + if (drv == NULL) + return; + if ((ifm->ifm_flags & IFF_UP) == 0 && + (drv->flags & IFF_UP) != 0) { wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", - event.interface_status.ifname); - wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); + drv->ifname); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, + NULL); + } else if ((ifm->ifm_flags & IFF_UP) != 0 && + (drv->flags & IFF_UP) == 0) { + wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP", + drv->ifname); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, + NULL); } + drv->flags = ifm->ifm_flags; break; } } @@ -1333,11 +1400,16 @@ wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res, result->caps = sr->isr_capinfo; result->qual = sr->isr_rssi; result->noise = sr->isr_noise; + +#ifdef __FreeBSD__ /* * the rssi value reported by the kernel is in 0.5dB steps relative to * the reported noise floor. see ieee80211_node.h for details. */ result->level = sr->isr_rssi / 2 + sr->isr_noise; +#else + result->level = sr->isr_rssi; +#endif pos = (u8 *)(result + 1); @@ -1504,7 +1576,7 @@ get80211opmode(struct bsd_driver_data *drv) (void) memset(&ifmr, 0, sizeof(ifmr)); (void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); - if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { + if (ioctl(drv->global->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) { if (ifmr.ifm_current & IFM_FLAG0) return IEEE80211_M_AHDEMO; @@ -1526,7 +1598,7 @@ get80211opmode(struct bsd_driver_data *drv) } static void * -wpa_driver_bsd_init(void *ctx, const char *ifname) +wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv) { #define GETPARAM(drv, param, v) \ (((v) = get80211param(drv, param)) != -1) @@ -1536,14 +1608,6 @@ wpa_driver_bsd_init(void *ctx, const char *ifname) if (drv == NULL) return NULL; - drv->event_buf_len = rtbuf_len(); - - drv->event_buf = os_malloc(drv->event_buf_len); - if (drv->event_buf == NULL) { - wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); - goto fail1; - } - /* * NB: We require the interface name be mappable to an index. * This implies we do not support having wpa_supplicant @@ -1554,24 +1618,12 @@ wpa_driver_bsd_init(void *ctx, const char *ifname) if (drv->ifindex == 0) { wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", __func__, ifname); - goto fail1; - } - drv->sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->sock < 0) - goto fail1; - - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - /* Down interface during setup. */ - if (bsd_ctrl_iface(drv, 0) < 0) goto fail; - - drv->route = socket(PF_ROUTE, SOCK_RAW, 0); - if (drv->route < 0) - goto fail; - eloop_register_read_sock(drv->route, - wpa_driver_bsd_event_receive, ctx, drv); + } drv->ctx = ctx; + drv->global = priv; + os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) { wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s", @@ -1592,13 +1644,15 @@ wpa_driver_bsd_init(void *ctx, const char *ifname) if (wpa_driver_bsd_capa(drv)) goto fail; + /* Down interface during setup. */ + if (bsd_ctrl_iface(drv, 0) < 0) + goto fail; + drv->opmode = get80211opmode(drv); + dl_list_add(&drv->global->ifaces, &drv->list); return drv; fail: - close(drv->sock); -fail1: - os_free(drv->event_buf); os_free(drv); return NULL; #undef GETPARAM @@ -1609,22 +1663,25 @@ wpa_driver_bsd_deinit(void *priv) { struct bsd_driver_data *drv = priv; - wpa_driver_bsd_set_wpa(drv, 0); - eloop_unregister_read_sock(drv->route); + if (drv->ifindex != 0 && !drv->if_removed) { + wpa_driver_bsd_set_wpa(drv, 0); - /* NB: mark interface down */ - bsd_ctrl_iface(drv, 0); + /* NB: mark interface down */ + bsd_ctrl_iface(drv, 0); - wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy); - if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0) - wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state", - __func__); + wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, + drv->prev_privacy); + + if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) + < 0) + wpa_printf(MSG_DEBUG, + "%s: failed to restore roaming state", + __func__); + } if (drv->sock_xmit != NULL) l2_packet_deinit(drv->sock_xmit); - (void) close(drv->route); /* ioctl socket */ - (void) close(drv->sock); /* event socket */ - os_free(drv->event_buf); + dl_list_del(&drv->list); os_free(drv); } @@ -1638,10 +1695,74 @@ wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) } #endif /* HOSTAPD */ +static void * +bsd_global_init(void *ctx) +{ + struct bsd_driver_global *global; + + global = os_zalloc(sizeof(*global)); + if (global == NULL) + return NULL; + + global->ctx = ctx; + dl_list_init(&global->ifaces); + + global->sock = socket(PF_INET, SOCK_DGRAM, 0); + if (global->sock < 0) { + wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", + strerror(errno)); + goto fail1; + } + + global->route = socket(PF_ROUTE, SOCK_RAW, 0); + if (global->route < 0) { + wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s", + strerror(errno)); + goto fail; + } + + global->event_buf_len = rtbuf_len(); + global->event_buf = os_malloc(global->event_buf_len); + if (global->event_buf == NULL) { + wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); + goto fail; + } + +#ifdef HOSTAPD + eloop_register_read_sock(global->route, bsd_wireless_event_receive, + NULL, global); + +#else /* HOSTAPD */ + eloop_register_read_sock(global->route, wpa_driver_bsd_event_receive, + NULL, global); +#endif /* HOSTAPD */ + + return global; + +fail: + close(global->sock); +fail1: + os_free(global); + return NULL; +} + +static void +bsd_global_deinit(void *priv) +{ + struct bsd_driver_global *global = priv; + + eloop_unregister_read_sock(global->route); + (void) close(global->route); + (void) close(global->sock); + os_free(global); +} + const struct wpa_driver_ops wpa_driver_bsd_ops = { .name = "bsd", .desc = "BSD 802.11 support", + .global_init = bsd_global_init, + .global_deinit = bsd_global_deinit, #ifdef HOSTAPD .hapd_init = bsd_init, .hapd_deinit = bsd_deinit, @@ -1654,7 +1775,7 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = { .sta_set_flags = bsd_set_sta_authorized, .commit = bsd_commit, #else /* HOSTAPD */ - .init = wpa_driver_bsd_init, + .init2 = wpa_driver_bsd_init, .deinit = wpa_driver_bsd_deinit, .get_bssid = wpa_driver_bsd_get_bssid, .get_ssid = wpa_driver_bsd_get_ssid, diff --git a/freebsd/contrib/wpa/src/drivers/driver_common.c b/freebsd/contrib/wpa/src/drivers/driver_common.c index 28f483e9..139829e4 100644 --- a/freebsd/contrib/wpa/src/drivers/driver_common.c +++ b/freebsd/contrib/wpa/src/drivers/driver_common.c @@ -82,6 +82,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(NEW_PEER_CANDIDATE); E2S(ACS_CHANNEL_SELECTED); E2S(DFS_CAC_STARTED); + E2S(P2P_LO_STOP); } return "UNKNOWN"; @@ -185,12 +186,12 @@ wpa_get_wowlan_triggers(const char *wowlan_triggers, start = buf; while (*start != '\0') { - while (isblank(*start)) + while (isblank((unsigned char) *start)) start++; if (*start == '\0') break; end = start; - while (!isblank(*end) && *end != '\0') + while (!isblank((unsigned char) *end) && *end != '\0') end++; last = *end == '\0'; *end = '\0'; @@ -220,3 +221,55 @@ out: os_free(buf); return triggers; } + + +const char * driver_flag_to_string(u64 flag) +{ +#define DF2S(x) case WPA_DRIVER_FLAGS_ ## x: return #x + switch (flag) { + DF2S(DRIVER_IE); + DF2S(SET_KEYS_AFTER_ASSOC); + DF2S(DFS_OFFLOAD); + DF2S(4WAY_HANDSHAKE); + DF2S(WIRED); + DF2S(SME); + DF2S(AP); + DF2S(SET_KEYS_AFTER_ASSOC_DONE); + DF2S(HT_2040_COEX); + DF2S(P2P_CONCURRENT); + DF2S(P2P_DEDICATED_INTERFACE); + DF2S(P2P_CAPABLE); + DF2S(AP_TEARDOWN_SUPPORT); + DF2S(P2P_MGMT_AND_NON_P2P); + DF2S(SANE_ERROR_CODES); + DF2S(OFFCHANNEL_TX); + DF2S(EAPOL_TX_STATUS); + DF2S(DEAUTH_TX_STATUS); + DF2S(BSS_SELECTION); + DF2S(TDLS_SUPPORT); + DF2S(TDLS_EXTERNAL_SETUP); + DF2S(PROBE_RESP_OFFLOAD); + DF2S(AP_UAPSD); + DF2S(INACTIVITY_TIMER); + DF2S(AP_MLME); + DF2S(SAE); + DF2S(OBSS_SCAN); + DF2S(IBSS); + DF2S(RADAR); + DF2S(DEDICATED_P2P_DEVICE); + DF2S(QOS_MAPPING); + DF2S(AP_CSA); + DF2S(MESH); + DF2S(ACS_OFFLOAD); + DF2S(KEY_MGMT_OFFLOAD); + DF2S(TDLS_CHANNEL_SWITCH); + DF2S(HT_IBSS); + DF2S(VHT_IBSS); + DF2S(SUPPORT_HW_MODE_ANY); + DF2S(OFFCHANNEL_SIMULTANEOUS); + DF2S(FULL_AP_CLIENT_STATE); + DF2S(P2P_LISTEN_OFFLOAD); + } + return "UNKNOWN"; +#undef DF2S +} diff --git a/freebsd/contrib/wpa/src/drivers/driver_ndis.c b/freebsd/contrib/wpa/src/drivers/driver_ndis.c index 6b3b26bc..98aa48ba 100644 --- a/freebsd/contrib/wpa/src/drivers/driver_ndis.c +++ b/freebsd/contrib/wpa/src/drivers/driver_ndis.c @@ -37,6 +37,7 @@ int close(int fd); #include "driver.h" #include "eloop.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" #include "driver_ndis.h" int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv); @@ -783,20 +784,7 @@ static int wpa_driver_ndis_scan(void *priv, static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) { - const u8 *end, *pos; - - pos = (const u8 *) (res + 1); - end = pos + res->ie_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; + return get_ie((const u8 *) (res + 1), res->ie_len, ie); } diff --git a/freebsd/contrib/wpa/src/drivers/driver_nl80211.h b/freebsd/contrib/wpa/src/drivers/driver_nl80211.h index 5c21e0fa..d0ec48c9 100644 --- a/freebsd/contrib/wpa/src/drivers/driver_nl80211.h +++ b/freebsd/contrib/wpa/src/drivers/driver_nl80211.h @@ -25,6 +25,7 @@ #endif /* CONFIG_LIBNL20 */ struct nl80211_global { + void *ctx; struct dl_list interfaces; int if_add_ifindex; u64 if_add_wdevid; @@ -84,6 +85,7 @@ struct wpa_driver_nl80211_data { struct dl_list list; struct dl_list wiphy_list; char phyname[32]; + unsigned int wiphy_idx; u8 perm_addr[ETH_ALEN]; void *ctx; int ifindex; @@ -94,6 +96,13 @@ struct wpa_driver_nl80211_data { struct wpa_driver_capa capa; u8 *extended_capa, *extended_capa_mask; unsigned int extended_capa_len; + struct drv_nl80211_ext_capa { + enum nl80211_iftype iftype; + u8 *ext_capa, *ext_capa_mask; + unsigned int ext_capa_len; + } iface_ext_capa[NL80211_IFTYPE_MAX]; + unsigned int num_iface_ext_capa; + int has_capability; int operstate; @@ -148,9 +157,16 @@ struct wpa_driver_nl80211_data { unsigned int setband_vendor_cmd_avail:1; unsigned int get_pref_freq_list:1; unsigned int set_prob_oper_freq:1; + unsigned int scan_vendor_cmd_avail:1; + unsigned int connect_reassoc:1; + unsigned int set_wifi_conf_vendor_cmd_avail:1; + u64 vendor_scan_cookie; u64 remain_on_chan_cookie; u64 send_action_cookie; +#define MAX_SEND_ACTION_COOKIES 20 + u64 send_action_cookies[MAX_SEND_ACTION_COOKIES]; + unsigned int num_send_action_cookies; unsigned int last_mgmt_freq; @@ -166,7 +182,10 @@ struct wpa_driver_nl80211_data { struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */ int default_if_indices[16]; + /* the AP/AP_VLAN iface that is in this bridge */ + int default_if_indices_reason[16]; int *if_indices; + int *if_indices_reason; int num_if_indices; /* From failed authentication command */ @@ -182,6 +201,13 @@ struct wpa_driver_nl80211_data { int auth_wep_tx_keyidx; int auth_local_state_change; int auth_p2p; + + /* + * Tells whether the last scan issued from wpa_supplicant was a normal + * scan (NL80211_CMD_TRIGGER_SCAN) or a vendor scan + * (NL80211_CMD_VENDOR). 0 if no pending scan request. + */ + int last_scan_cmd; }; struct nl_msg; @@ -233,6 +259,8 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags); int process_global_event(struct nl_msg *msg, void *arg); int process_bss_event(struct nl_msg *msg, void *arg); +const char * nl80211_iftype_str(enum nl80211_iftype mode); + #ifdef ANDROID int android_nl_socket_set_nonblocking(struct nl_handle *handle); int android_pno_start(struct i802_bss *bss, @@ -267,11 +295,13 @@ void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx); int wpa_driver_nl80211_scan(struct i802_bss *bss, struct wpa_driver_scan_params *params); int wpa_driver_nl80211_sched_scan(void *priv, - struct wpa_driver_scan_params *params, - u32 interval); + struct wpa_driver_scan_params *params); int wpa_driver_nl80211_stop_sched_scan(void *priv); struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv); void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv); -const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie); +int wpa_driver_nl80211_abort_scan(void *priv); +int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss, + struct wpa_driver_scan_params *params); +int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len); #endif /* DRIVER_NL80211_H */ diff --git a/freebsd/contrib/wpa/src/drivers/driver_wired.c b/freebsd/contrib/wpa/src/drivers/driver_wired.c index b30d47cf..372bf791 100644 --- a/freebsd/contrib/wpa/src/drivers/driver_wired.c +++ b/freebsd/contrib/wpa/src/drivers/driver_wired.c @@ -10,12 +10,17 @@ */ #include "includes.h" + +#include "common.h" +#include "eloop.h" +#include "driver.h" + #include <sys/ioctl.h> +#undef IFNAMSIZ #include <net/if.h> #ifdef __linux__ #include <netpacket/packet.h> #include <net/if_arp.h> -#include <net/if.h> #endif /* __linux__ */ #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) #include <net/if_dl.h> @@ -25,10 +30,6 @@ #include <sys/sockio.h> #endif /* __sun__ */ -#include "common.h" -#include "eloop.h" -#include "driver.h" - #ifdef _MSC_VER #pragma pack(push, 1) #endif /* _MSC_VER */ @@ -472,6 +473,7 @@ static int wpa_driver_wired_set_ifflags(const char *ifname, int flags) return 0; } + #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) static int wpa_driver_wired_get_ifstatus(const char *ifname, int *status) { @@ -559,7 +561,7 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add) static void * wpa_driver_wired_init(void *ctx, const char *ifname) { struct wpa_driver_wired_data *drv; - int flags, status; + int flags; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) diff --git a/freebsd/contrib/wpa/src/drivers/drivers.c b/freebsd/contrib/wpa/src/drivers/drivers.c index 5a0b58c2..ac83600e 100644 --- a/freebsd/contrib/wpa/src/drivers/drivers.c +++ b/freebsd/contrib/wpa/src/drivers/drivers.c @@ -12,42 +12,6 @@ #include "utils/common.h" #include "driver.h" -#ifdef CONFIG_DRIVER_WEXT -extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ -#endif /* CONFIG_DRIVER_WEXT */ -#ifdef CONFIG_DRIVER_NL80211 -extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */ -#endif /* CONFIG_DRIVER_NL80211 */ -#ifdef CONFIG_DRIVER_HOSTAP -extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ -#endif /* CONFIG_DRIVER_HOSTAP */ -#ifdef CONFIG_DRIVER_BSD -extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ -#endif /* CONFIG_DRIVER_BSD */ -#ifdef CONFIG_DRIVER_OPENBSD -extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */ -#endif /* CONFIG_DRIVER_OPENBSD */ -#ifdef CONFIG_DRIVER_NDIS -extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */ -#endif /* CONFIG_DRIVER_NDIS */ -#ifdef CONFIG_DRIVER_WIRED -extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */ -#endif /* CONFIG_DRIVER_WIRED */ -#ifdef CONFIG_DRIVER_MACSEC_QCA - /* driver_macsec_qca.c */ -extern struct wpa_driver_ops wpa_driver_macsec_qca_ops; -#endif /* CONFIG_DRIVER_MACSEC_QCA */ -#ifdef CONFIG_DRIVER_ROBOSWITCH -/* driver_roboswitch.c */ -extern struct wpa_driver_ops wpa_driver_roboswitch_ops; -#endif /* CONFIG_DRIVER_ROBOSWITCH */ -#ifdef CONFIG_DRIVER_ATHEROS -extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ -#endif /* CONFIG_DRIVER_ATHEROS */ -#ifdef CONFIG_DRIVER_NONE -extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ -#endif /* CONFIG_DRIVER_NONE */ - const struct wpa_driver_ops *const wpa_drivers[] = { diff --git a/freebsd/contrib/wpa/src/eap_peer/eap.c b/freebsd/contrib/wpa/src/eap_peer/eap.c index cfaf201a..6a183071 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap.c @@ -50,6 +50,8 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req); static const char * eap_sm_method_state_txt(EapMethodState state); static const char * eap_sm_decision_txt(EapDecision decision); #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ +static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field, + const char *msg, size_t msglen); @@ -190,6 +192,14 @@ SM_STATE(EAP, INITIALIZE) */ eapol_set_bool(sm, EAPOL_eapResp, FALSE); eapol_set_bool(sm, EAPOL_eapNoResp, FALSE); + /* + * RFC 4137 does not reset ignore here, but since it is possible for + * some method code paths to end up not setting ignore=FALSE, clear the + * value here to avoid issues if a previous authentication attempt + * failed with ignore=TRUE being left behind in the last + * m.check(eapReqData) operation. + */ + sm->ignore = 0; sm->num_rounds = 0; sm->prev_failure = 0; sm->expected_failure = 0; @@ -314,11 +324,14 @@ SM_STATE(EAP, GET_METHOD) wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: " "vendor %u method %u (%s)", sm->reqVendor, method, sm->m->name); - if (reinit) + if (reinit) { sm->eap_method_priv = sm->m->init_for_reauth( sm, sm->eap_method_priv); - else + } else { + sm->waiting_ext_cert_check = 0; + sm->ext_cert_check = 0; sm->eap_method_priv = sm->m->init(sm); + } if (sm->eap_method_priv == NULL) { struct eap_peer_config *config = eap_get_config(sm); @@ -1375,13 +1388,10 @@ static int eap_sm_imsi_identity(struct eap_sm *sm, return 0; } -#endif /* PCSC_FUNCS */ - static int eap_sm_set_scard_pin(struct eap_sm *sm, struct eap_peer_config *conf) { -#ifdef PCSC_FUNCS if (scard_set_pin(sm->scard_ctx, conf->pin)) { /* * Make sure the same PIN is not tried again in order to avoid @@ -1395,24 +1405,20 @@ static int eap_sm_set_scard_pin(struct eap_sm *sm, return -1; } return 0; -#else /* PCSC_FUNCS */ - return -1; -#endif /* PCSC_FUNCS */ } + static int eap_sm_get_scard_identity(struct eap_sm *sm, struct eap_peer_config *conf) { -#ifdef PCSC_FUNCS if (eap_sm_set_scard_pin(sm, conf)) return -1; return eap_sm_imsi_identity(sm, conf); -#else /* PCSC_FUNCS */ - return -1; -#endif /* PCSC_FUNCS */ } +#endif /* PCSC_FUNCS */ + /** * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network @@ -1455,23 +1461,27 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted) identity, identity_len); } - if (identity == NULL) { - wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity " - "configuration was not available"); - if (config->pcsc) { + if (config->pcsc) { +#ifdef PCSC_FUNCS + if (!identity) { if (eap_sm_get_scard_identity(sm, config) < 0) return NULL; identity = config->identity; identity_len = config->identity_len; - wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from " - "IMSI", identity, identity_len); - } else { - eap_sm_request_identity(sm); + wpa_hexdump_ascii(MSG_DEBUG, + "permanent identity from IMSI", + identity, identity_len); + } else if (eap_sm_set_scard_pin(sm, config) < 0) { return NULL; } - } else if (config->pcsc) { - if (eap_sm_set_scard_pin(sm, config) < 0) - return NULL; +#else /* PCSC_FUNCS */ + return NULL; +#endif /* PCSC_FUNCS */ + } else if (!identity) { + wpa_printf(MSG_WARNING, + "EAP: buildIdentity: identity configuration was not available"); + eap_sm_request_identity(sm); + return NULL; } resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len, @@ -1512,15 +1522,9 @@ static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req) static struct wpabuf * eap_sm_buildNotify(int id) { - struct wpabuf *resp; - wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification"); - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - return resp; + return eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0, + EAP_CODE_RESPONSE, id); } @@ -1852,6 +1856,11 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, case TLS_CERT_CHAIN_SUCCESS: eap_notify_status(sm, "remote certificate verification", "success"); + if (sm->ext_cert_check) { + sm->waiting_ext_cert_check = 1; + eap_sm_request(sm, WPA_CTRL_REQ_EXT_CERT_CHECK, + NULL, 0); + } break; case TLS_CERT_CHAIN_FAILURE: wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR @@ -2174,10 +2183,10 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose) #endif /* CONFIG_CTRL_IFACE */ -#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field, const char *msg, size_t msglen) { +#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) struct eap_peer_config *config; const char *txt = NULL; char *tmp; @@ -2226,16 +2235,17 @@ static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field, case WPA_CTRL_REQ_SIM: txt = msg; break; + case WPA_CTRL_REQ_EXT_CERT_CHECK: + break; default: return; } if (sm->eapol_cb->eap_param_needed) sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt); -} -#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ -#define eap_sm_request(sm, type, msg, msglen) do { } while (0) #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ +} + const char * eap_sm_get_method_name(struct eap_sm *sm) { diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_config.h b/freebsd/contrib/wpa/src/eap_peer/eap_config.h index 2b1a1d5e..f9800726 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_config.h +++ b/freebsd/contrib/wpa/src/eap_peer/eap_config.h @@ -181,13 +181,13 @@ struct eap_peer_config { * subject_match - Constraint for server certificate subject * * This substring is matched against the subject of the authentication - * server certificate. If this string is set, the server sertificate is + * server certificate. If this string is set, the server certificate is * only accepted if it contains this string in the subject. The subject * string is in following format: * * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com * - * Note: Since this is a substring match, this cannot be used securily + * Note: Since this is a substring match, this cannot be used securely * to do a suffix match against a possible domain name in the CN entry. * For such a use case, domain_suffix_match should be used instead. */ @@ -198,7 +198,7 @@ struct eap_peer_config { * * Semicolon separated string of entries to be matched against the * alternative subject name of the authentication server certificate. - * If this string is set, the server sertificate is only accepted if it + * If this string is set, the server certificate is only accepted if it * contains one of the entries in an alternative subject name * extension. * @@ -739,6 +739,20 @@ struct eap_peer_config { * erp - Whether EAP Re-authentication Protocol (ERP) is enabled */ int erp; + + /** + * pending_ext_cert_check - External server certificate check status + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request external + * validation of server certificate chain. + */ + enum { + NO_CHECK = 0, + PENDING_CHECK, + EXT_CERT_CHECK_GOOD, + EXT_CERT_CHECK_BAD, + } pending_ext_cert_check; }; diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_gtc.c b/freebsd/contrib/wpa/src/eap_peer/eap_gtc.c index 2ffc142c..cacf3d41 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_gtc.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_gtc.c @@ -129,7 +129,6 @@ static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv, int eap_peer_gtc_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); @@ -140,8 +139,5 @@ int eap_peer_gtc_register(void) eap->deinit = eap_gtc_deinit; eap->process = eap_gtc_process; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_i.h b/freebsd/contrib/wpa/src/eap_peer/eap_i.h index 99b44dae..6ab24834 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_i.h +++ b/freebsd/contrib/wpa/src/eap_peer/eap_i.h @@ -366,6 +366,8 @@ struct eap_sm { int external_sim; unsigned int expected_failure:1; + unsigned int ext_cert_check:1; + unsigned int waiting_ext_cert_check:1; struct dl_list erp_keys; /* struct eap_erp_key */ }; diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_leap.c b/freebsd/contrib/wpa/src/eap_peer/eap_leap.c index e765af14..af63bf88 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_leap.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_leap.c @@ -395,7 +395,6 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) int eap_peer_leap_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP"); @@ -408,8 +407,5 @@ int eap_peer_leap_register(void) eap->isKeyAvailable = eap_leap_isKeyAvailable; eap->getKey = eap_leap_getKey; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_md5.c b/freebsd/contrib/wpa/src/eap_peer/eap_md5.c index 145bfa8f..2cc66e6d 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_md5.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_md5.c @@ -104,7 +104,6 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv, int eap_peer_md5_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5"); @@ -115,8 +114,5 @@ int eap_peer_md5_register(void) eap->deinit = eap_md5_deinit; eap->process = eap_md5_process; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_methods.c b/freebsd/contrib/wpa/src/eap_peer/eap_methods.c index 44b4af92..23004eac 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_methods.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_methods.c @@ -23,6 +23,8 @@ static struct eap_method *eap_methods = NULL; +static void eap_peer_method_free(struct eap_method *method); + /** * eap_peer_get_eap_method - Get EAP method based on type number @@ -300,7 +302,7 @@ struct eap_method * eap_peer_method_alloc(int version, int vendor, * eap_peer_method_free - Free EAP peer method structure * @method: Method structure allocated with eap_peer_method_alloc() */ -void eap_peer_method_free(struct eap_method *method) +static void eap_peer_method_free(struct eap_method *method) { os_free(method); } @@ -308,26 +310,31 @@ void eap_peer_method_free(struct eap_method *method) /** * eap_peer_method_register - Register an EAP peer method - * @method: EAP method to register + * @method: EAP method to register from eap_peer_method_alloc() * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method * has already been registered * * Each EAP peer method needs to call this function to register itself as a - * supported EAP method. + * supported EAP method. The caller must not free the allocated method data + * regardless of the return value. */ int eap_peer_method_register(struct eap_method *method) { struct eap_method *m, *last = NULL; if (method == NULL || method->name == NULL || - method->version != EAP_PEER_METHOD_INTERFACE_VERSION) + method->version != EAP_PEER_METHOD_INTERFACE_VERSION) { + eap_peer_method_free(method); return -1; + } for (m = eap_methods; m; m = m->next) { if ((m->vendor == method->vendor && m->method == method->method) || - os_strcmp(m->name, method->name) == 0) + os_strcmp(m->name, method->name) == 0) { + eap_peer_method_free(method); return -2; + } last = m; } diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_methods.h b/freebsd/contrib/wpa/src/eap_peer/eap_methods.h index e35c919a..b96b211d 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_methods.h +++ b/freebsd/contrib/wpa/src/eap_peer/eap_methods.h @@ -16,7 +16,6 @@ const struct eap_method * eap_peer_get_methods(size_t *count); struct eap_method * eap_peer_method_alloc(int version, int vendor, EapType method, const char *name); -void eap_peer_method_free(struct eap_method *method); int eap_peer_method_register(struct eap_method *method); diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_mschapv2.c b/freebsd/contrib/wpa/src/eap_peer/eap_mschapv2.c index 18bb04c2..9193a772 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_mschapv2.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_mschapv2.c @@ -882,7 +882,6 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) int eap_peer_mschapv2_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, @@ -896,8 +895,5 @@ int eap_peer_mschapv2_register(void) eap->isKeyAvailable = eap_mschapv2_isKeyAvailable; eap->getKey = eap_mschapv2_getKey; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_otp.c b/freebsd/contrib/wpa/src/eap_peer/eap_otp.c index d4d8bc1c..f375d438 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_otp.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_otp.c @@ -85,7 +85,6 @@ static struct wpabuf * eap_otp_process(struct eap_sm *sm, void *priv, int eap_peer_otp_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_OTP, "OTP"); @@ -96,8 +95,5 @@ int eap_peer_otp_register(void) eap->deinit = eap_otp_deinit; eap->process = eap_otp_process; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_peap.c b/freebsd/contrib/wpa/src/eap_peer/eap_peap.c index 19afa1cf..ab270bbc 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_peap.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_peap.c @@ -2,7 +2,7 @@ /* * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) - * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -61,6 +61,7 @@ struct eap_peap_data { size_t id_len; struct wpabuf *pending_phase2_req; + struct wpabuf *pending_resp; enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; int crypto_binding_used; u8 binding_nonce[32]; @@ -71,8 +72,8 @@ struct eap_peap_data { }; -static int eap_peap_parse_phase1(struct eap_peap_data *data, - const char *phase1) +static void eap_peap_parse_phase1(struct eap_peap_data *data, + const char *phase1) { const char *pos; @@ -127,8 +128,6 @@ static int eap_peap_parse_phase1(struct eap_peap_data *data, wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); } #endif /* EAP_TNC */ - - return 0; } @@ -146,11 +145,8 @@ static void * eap_peap_init(struct eap_sm *sm) data->peap_outer_success = 2; data->crypto_binding = OPTIONAL_BINDING; - if (config && config->phase1 && - eap_peap_parse_phase1(data, config->phase1) < 0) { - eap_peap_deinit(sm, data); - return NULL; - } + if (config && config->phase1) + eap_peap_parse_phase1(data, config->phase1); if (eap_peer_select_phase2_methods(config, "auth=", &data->phase2_types, @@ -193,6 +189,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv) eap_peap_free_key(data); os_free(data->session_id); wpabuf_free(data->pending_phase2_req); + wpabuf_free(data->pending_resp); os_free(data); } @@ -258,6 +255,7 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) { u8 *tk; u8 isk[32], imck[60]; + int resumed; /* * Tunnel key (TK) is the first 60 octets of the key generated by @@ -268,8 +266,12 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) return -1; wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); - if (data->reauth && - tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { + resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn); + wpa_printf(MSG_DEBUG, + "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d", + data->reauth, resumed, data->phase2_eap_started, + data->phase2_success); + if (data->reauth && !data->phase2_eap_started && resumed) { /* Fast-connect: IPMK|CMK = TK */ os_memcpy(data->ipmk, tk, 40); wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK", @@ -339,7 +341,8 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm, addr[0], len[0]); wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", addr[1], len[1]); - hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); + if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0) + return -1; wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN); data->crypto_binding_used = 1; @@ -650,6 +653,7 @@ static int eap_peap_phase2_request(struct eap_sm *sm, if (*resp == NULL) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; + wpabuf_free(buf); return -1; } wpabuf_put_buf(*resp, buf); @@ -1008,6 +1012,34 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, !data->resuming) { res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp); } else { + if (sm->waiting_ext_cert_check && data->pending_resp) { + struct eap_peer_config *config = eap_get_config(sm); + + if (config->pending_ext_cert_check == + EXT_CERT_CHECK_GOOD) { + wpa_printf(MSG_DEBUG, + "EAP-PEAP: External certificate check succeeded - continue handshake"); + resp = data->pending_resp; + data->pending_resp = NULL; + sm->waiting_ext_cert_check = 0; + return resp; + } + + if (config->pending_ext_cert_check == + EXT_CERT_CHECK_BAD) { + wpa_printf(MSG_DEBUG, + "EAP-PEAP: External certificate check failed - force authentication failure"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + sm->waiting_ext_cert_check = 0; + return NULL; + } + + wpa_printf(MSG_DEBUG, + "EAP-PEAP: Continuing to wait external server certificate validation"); + return NULL; + } + res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_PEAP, data->peap_version, id, &msg, @@ -1020,6 +1052,16 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, ret->decision = DECISION_FAIL; return resp; } + + + if (sm->waiting_ext_cert_check) { + wpa_printf(MSG_DEBUG, + "EAP-PEAP: Waiting external server certificate validation"); + wpabuf_free(data->pending_resp); + data->pending_resp = resp; + return NULL; + } + if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { char *label; wpa_printf(MSG_DEBUG, @@ -1125,6 +1167,8 @@ static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv) struct eap_peap_data *data = priv; wpabuf_free(data->pending_phase2_req); data->pending_phase2_req = NULL; + wpabuf_free(data->pending_resp); + data->pending_resp = NULL; data->crypto_binding_used = 0; } @@ -1239,7 +1283,6 @@ static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len) int eap_peer_peap_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); @@ -1257,8 +1300,5 @@ int eap_peer_peap_register(void) eap->init_for_reauth = eap_peap_init_for_reauth; eap->getSessionId = eap_peap_get_session_id; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_psk.c b/freebsd/contrib/wpa/src/eap_peer/eap_psk.c index f91c9b39..49ed1736 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_psk.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_psk.c @@ -482,7 +482,6 @@ static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) int eap_peer_psk_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); @@ -497,8 +496,5 @@ int eap_peer_psk_register(void) eap->getSessionId = eap_psk_get_session_id; eap->get_emsk = eap_psk_get_emsk; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_tls.c b/freebsd/contrib/wpa/src/eap_peer/eap_tls.c index 8ca6db9c..35afcf77 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_tls.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_tls.c @@ -2,7 +2,7 @@ /* * EAP peer method: EAP-TLS (RFC 2716) - * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -27,6 +27,7 @@ struct eap_tls_data { size_t id_len; void *ssl_ctx; u8 eap_type; + struct wpabuf *pending_resp; }; @@ -144,6 +145,7 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv) eap_peer_tls_ssl_deinit(sm, &data->ssl); eap_tls_free_key(data); os_free(data->session_id); + wpabuf_free(data->pending_resp); os_free(data); } @@ -218,6 +220,32 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, struct eap_tls_data *data = priv; struct wpabuf msg; + if (sm->waiting_ext_cert_check && data->pending_resp) { + struct eap_peer_config *config = eap_get_config(sm); + + if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) { + wpa_printf(MSG_DEBUG, + "EAP-TLS: External certificate check succeeded - continue handshake"); + resp = data->pending_resp; + data->pending_resp = NULL; + sm->waiting_ext_cert_check = 0; + return resp; + } + + if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) { + wpa_printf(MSG_DEBUG, + "EAP-TLS: External certificate check failed - force authentication failure"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + sm->waiting_ext_cert_check = 0; + return NULL; + } + + wpa_printf(MSG_DEBUG, + "EAP-TLS: Continuing to wait external server certificate validation"); + return NULL; + } + pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret, reqData, &left, &flags); if (pos == NULL) @@ -239,6 +267,14 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, return eap_tls_failure(sm, data, ret, res, resp, id); } + if (sm->waiting_ext_cert_check) { + wpa_printf(MSG_DEBUG, + "EAP-TLS: Waiting external server certificate validation"); + wpabuf_free(data->pending_resp); + data->pending_resp = resp; + return NULL; + } + if (tls_connection_established(data->ssl_ctx, data->ssl.conn)) eap_tls_success(sm, data, ret); @@ -260,6 +296,10 @@ static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv) static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) { + struct eap_tls_data *data = priv; + + wpabuf_free(data->pending_resp); + data->pending_resp = NULL; } @@ -352,7 +392,6 @@ static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) int eap_peer_tls_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); @@ -371,10 +410,7 @@ int eap_peer_tls_register(void) eap->init_for_reauth = eap_tls_init_for_reauth; eap->get_emsk = eap_tls_get_emsk; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } @@ -382,7 +418,6 @@ int eap_peer_tls_register(void) int eap_peer_unauth_tls_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_UNAUTH_TLS, @@ -401,10 +436,7 @@ int eap_peer_unauth_tls_register(void) eap->init_for_reauth = eap_tls_init_for_reauth; eap->get_emsk = eap_tls_get_emsk; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } #endif /* EAP_UNAUTH_TLS */ @@ -413,7 +445,6 @@ int eap_peer_unauth_tls_register(void) int eap_peer_wfa_unauth_tls_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_WFA_NEW, @@ -433,9 +464,6 @@ int eap_peer_wfa_unauth_tls_register(void) eap->init_for_reauth = eap_tls_init_for_reauth; eap->get_emsk = eap_tls_get_emsk; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } #endif /* CONFIG_HS20 */ diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_tls_common.c b/freebsd/contrib/wpa/src/eap_peer/eap_tls_common.c index ff6c937c..8908dc2f 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_tls_common.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_tls_common.c @@ -82,6 +82,10 @@ static void eap_tls_params_flags(struct tls_connection_params *params, params->flags |= TLS_CONN_DISABLE_TLSv1_2; if (os_strstr(txt, "tls_disable_tlsv1_2=0")) params->flags &= ~TLS_CONN_DISABLE_TLSv1_2; + if (os_strstr(txt, "tls_ext_cert_check=1")) + params->flags |= TLS_CONN_EXT_CERT_CHECK; + if (os_strstr(txt, "tls_ext_cert_check=0")) + params->flags &= ~TLS_CONN_EXT_CERT_CHECK; } @@ -179,6 +183,8 @@ static int eap_tls_params_from_conf(struct eap_sm *sm, params->openssl_ciphers = config->openssl_ciphers; + sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK); + return 0; } @@ -192,8 +198,10 @@ static int eap_tls_init_connection(struct eap_sm *sm, if (config->ocsp) params->flags |= TLS_CONN_REQUEST_OCSP; - if (config->ocsp == 2) + if (config->ocsp >= 2) params->flags |= TLS_CONN_REQUIRE_OCSP; + if (config->ocsp == 3) + params->flags |= TLS_CONN_REQUIRE_OCSP_ALL; data->conn = tls_connection_init(data->ssl_ctx); if (data->conn == NULL) { wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " @@ -322,8 +330,8 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, if (out == NULL) return NULL; - if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0, - out, len)) { + if (tls_connection_export_key(data->ssl_ctx, data->conn, label, out, + len)) { os_free(out); return NULL; } @@ -352,10 +360,8 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, struct tls_random keys; u8 *out; - if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys)) - return NULL; - - if (keys.client_random == NULL || keys.server_random == NULL) + if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys) || + keys.client_random == NULL || keys.server_random == NULL) return NULL; *len = 1 + keys.client_random_len + keys.server_random_len; @@ -1037,6 +1043,9 @@ int eap_peer_select_phase2_methods(struct eap_peer_config *config, if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " "method '%s'", start); + os_free(methods); + os_free(buf); + return -1; } else { num_methods++; _methods = os_realloc_array(methods, num_methods, diff --git a/freebsd/contrib/wpa/src/eap_peer/eap_ttls.c b/freebsd/contrib/wpa/src/eap_peer/eap_ttls.c index 55788774..f9601e45 100644 --- a/freebsd/contrib/wpa/src/eap_peer/eap_ttls.c +++ b/freebsd/contrib/wpa/src/eap_peer/eap_ttls.c @@ -2,7 +2,7 @@ /* * EAP peer method: EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -37,6 +37,7 @@ struct eap_ttls_data { void *phase2_priv; int phase2_success; int phase2_start; + EapDecision decision_succ; enum phase2_types { EAP_TTLS_PHASE2_EAP, @@ -60,6 +61,7 @@ struct eap_ttls_data { size_t id_len; struct wpabuf *pending_phase2_req; + struct wpabuf *pending_resp; #ifdef EAP_TNC int ready_for_tnc; @@ -72,6 +74,7 @@ static void * eap_ttls_init(struct eap_sm *sm) { struct eap_ttls_data *data; struct eap_peer_config *config = eap_get_config(sm); + int selected_non_eap; char *selected; data = os_zalloc(sizeof(*data)); @@ -79,26 +82,67 @@ static void * eap_ttls_init(struct eap_sm *sm) return NULL; data->ttls_version = EAP_TTLS_VERSION; selected = "EAP"; + selected_non_eap = 0; data->phase2_type = EAP_TTLS_PHASE2_EAP; + /* + * Either one auth= type or one or more autheap= methods can be + * specified. + */ if (config && config->phase2) { + const char *token, *last = NULL; + + while ((token = cstr_token(config->phase2, " \t", &last))) { + if (os_strncmp(token, "auth=", 5) != 0) + continue; + token += 5; + + if (last - token == 8 && + os_strncmp(token, "MSCHAPV2", 8) == 0) { + selected = "MSCHAPV2"; + data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; + } else if (last - token == 6 && + os_strncmp(token, "MSCHAP", 6) == 0) { + selected = "MSCHAP"; + data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; + } else if (last - token == 3 && + os_strncmp(token, "PAP", 3) == 0) { + selected = "PAP"; + data->phase2_type = EAP_TTLS_PHASE2_PAP; + } else if (last - token == 4 && + os_strncmp(token, "CHAP", 4) == 0) { + selected = "CHAP"; + data->phase2_type = EAP_TTLS_PHASE2_CHAP; + } else { + wpa_printf(MSG_ERROR, + "EAP-TTLS: Unsupported Phase2 type '%s'", + token); + eap_ttls_deinit(sm, data); + return NULL; + } + + if (selected_non_eap) { + wpa_printf(MSG_ERROR, + "EAP-TTLS: Only one Phase2 type can be specified"); + eap_ttls_deinit(sm, data); + return NULL; + } + + selected_non_eap = 1; + } + if (os_strstr(config->phase2, "autheap=")) { + if (selected_non_eap) { + wpa_printf(MSG_ERROR, + "EAP-TTLS: Both auth= and autheap= params cannot be specified"); + eap_ttls_deinit(sm, data); + return NULL; + } selected = "EAP"; data->phase2_type = EAP_TTLS_PHASE2_EAP; - } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) { - selected = "MSCHAPV2"; - data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; - } else if (os_strstr(config->phase2, "auth=MSCHAP")) { - selected = "MSCHAP"; - data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; - } else if (os_strstr(config->phase2, "auth=PAP")) { - selected = "PAP"; - data->phase2_type = EAP_TTLS_PHASE2_PAP; - } else if (os_strstr(config->phase2, "auth=CHAP")) { - selected = "CHAP"; - data->phase2_type = EAP_TTLS_PHASE2_CHAP; } } + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { @@ -155,6 +199,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv) eap_ttls_free_key(data); os_free(data->session_id); wpabuf_free(data->pending_phase2_req); + wpabuf_free(data->pending_resp); os_free(data); } @@ -1410,6 +1455,32 @@ static int eap_ttls_process_handshake(struct eap_sm *sm, { int res; + if (sm->waiting_ext_cert_check && data->pending_resp) { + struct eap_peer_config *config = eap_get_config(sm); + + if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) { + wpa_printf(MSG_DEBUG, + "EAP-TTLS: External certificate check succeeded - continue handshake"); + *out_data = data->pending_resp; + data->pending_resp = NULL; + sm->waiting_ext_cert_check = 0; + return 0; + } + + if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) { + wpa_printf(MSG_DEBUG, + "EAP-TTLS: External certificate check failed - force authentication failure"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + sm->waiting_ext_cert_check = 0; + return 0; + } + + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Continuing to wait external server certificate validation"); + return 0; + } + res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, data->ttls_version, identifier, in_data, out_data); @@ -1420,6 +1491,15 @@ static int eap_ttls_process_handshake(struct eap_sm *sm, return -1; } + if (sm->waiting_ext_cert_check) { + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Waiting external server certificate validation"); + wpabuf_free(data->pending_resp); + data->pending_resp = *out_data; + *out_data = NULL; + return 0; + } + if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to " "Phase 2"); @@ -1470,6 +1550,7 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " "completed successfully"); data->phase2_success = 1; + data->decision_succ = ret->decision; #ifdef EAP_TNC if (!data->ready_for_tnc && !data->tnc_started) { /* @@ -1487,6 +1568,18 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " "completed successfully (MAY_CONT)"); data->phase2_success = 1; + data->decision_succ = ret->decision; + } else if (data->decision_succ != DECISION_FAIL && + data->phase2_success && + !data->ssl.tls_out) { + /* + * This is needed to cover the case where the final Phase 2 + * message gets fragmented since fragmentation clears + * decision back to FAIL. + */ + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Restore success decision after fragmented frame sent completely"); + ret->decision = data->decision_succ; } } @@ -1559,6 +1652,9 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) struct eap_ttls_data *data = priv; wpabuf_free(data->pending_phase2_req); data->pending_phase2_req = NULL; + wpabuf_free(data->pending_resp); + data->pending_resp = NULL; + data->decision_succ = DECISION_FAIL; #ifdef EAP_TNC data->ready_for_tnc = 0; data->tnc_started = 0; @@ -1697,7 +1793,6 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) int eap_peer_ttls_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); @@ -1716,8 +1811,5 @@ int eap_peer_ttls_register(void) eap->init_for_reauth = eap_ttls_init_for_reauth; eap->get_emsk = eap_ttls_get_emsk; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); } diff --git a/freebsd/contrib/wpa/src/eap_server/eap_methods.h b/freebsd/contrib/wpa/src/eap_server/eap_methods.h index 0baa3279..3bf1495f 100644 --- a/freebsd/contrib/wpa/src/eap_server/eap_methods.h +++ b/freebsd/contrib/wpa/src/eap_server/eap_methods.h @@ -15,7 +15,6 @@ const struct eap_method * eap_server_get_eap_method(int vendor, EapType method); struct eap_method * eap_server_method_alloc(int version, int vendor, EapType method, const char *name); -void eap_server_method_free(struct eap_method *method); int eap_server_method_register(struct eap_method *method); EapType eap_server_get_type(const char *name, int *vendor); diff --git a/freebsd/contrib/wpa/src/eapol_supp/eapol_supp_sm.c b/freebsd/contrib/wpa/src/eapol_supp/eapol_supp_sm.c index e633d7c1..938e0d05 100644 --- a/freebsd/contrib/wpa/src/eapol_supp/eapol_supp_sm.c +++ b/freebsd/contrib/wpa/src/eapol_supp/eapol_supp_sm.c @@ -316,6 +316,16 @@ SM_STATE(SUPP_PAE, RESTART) { SM_ENTRY(SUPP_PAE, RESTART); sm->eapRestart = TRUE; + if (sm->altAccept) { + /* + * Prevent EAP peer state machine from failing due to prior + * external EAP success notification (altSuccess=TRUE in the + * IDLE state could result in a transition to the FAILURE state. + */ + wpa_printf(MSG_DEBUG, "EAPOL: Clearing prior altAccept TRUE"); + sm->eapSuccess = FALSE; + sm->altAccept = FALSE; + } } diff --git a/freebsd/contrib/wpa/src/p2p/p2p.h b/freebsd/contrib/wpa/src/p2p/p2p.h index b4060be4..7b18dcfc 100644 --- a/freebsd/contrib/wpa/src/p2p/p2p.h +++ b/freebsd/contrib/wpa/src/p2p/p2p.h @@ -31,7 +31,7 @@ /** * P2P_MAX_REG_CLASSES - Maximum number of regulatory classes */ -#define P2P_MAX_REG_CLASSES 10 +#define P2P_MAX_REG_CLASSES 15 /** * P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class @@ -99,6 +99,10 @@ struct p2p_go_neg_results { int vht; + u8 max_oper_chwidth; + + unsigned int vht_center_freq2; + /** * ssid - SSID of the group */ @@ -224,6 +228,16 @@ struct p2ps_provision { u8 cpt_priority[P2PS_FEATURE_CAPAB_CPT_MAX + 1]; /** + * force_freq - The only allowed channel frequency in MHz or 0. + */ + unsigned int force_freq; + + /** + * pref_freq - Preferred operating frequency in MHz or 0. + */ + unsigned int pref_freq; + + /** * info - Vendor defined extra Provisioning information */ char info[0]; @@ -1024,6 +1038,8 @@ struct p2p_config { * @ssid_len: Buffer for returning length of @ssid * @group_iface: Buffer for returning whether a separate group interface * would be used + * @freq: Variable for returning the current operating frequency of a + * currently running P2P GO. * Returns: 1 if GO info found, 0 otherwise * * This is used to compose New Group settings (SSID, and intended @@ -1031,7 +1047,8 @@ struct p2p_config { * result in our being an autonomous GO. */ int (*get_go_info)(void *ctx, u8 *intended_addr, - u8 *ssid, size_t *ssid_len, int *group_iface); + u8 *ssid, size_t *ssid_len, int *group_iface, + unsigned int *freq); /** * remove_stale_groups - Remove stale P2PS groups @@ -1056,7 +1073,9 @@ struct p2p_config { const u8 *persist_ssid, size_t persist_ssid_size, int response_done, int prov_start, const char *session_info, - const u8 *feat_cap, size_t feat_cap_len); + const u8 *feat_cap, size_t feat_cap_len, + unsigned int freq, const u8 *group_ssid, + size_t group_ssid_len); /** * prov_disc_resp_cb - Callback for indicating completion of PD Response @@ -1070,14 +1089,20 @@ struct p2p_config { /** * p2ps_group_capability - Determine group capability + * @ctx: Callback context from cb_ctx + * @incoming: Peer requested roles, expressed with P2PS_SETUP_* bitmap. + * @role: Local roles, expressed with P2PS_SETUP_* bitmap. + * @force_freq: Variable for returning forced frequency for the group. + * @pref_freq: Variable for returning preferred frequency for the group. + * Returns: P2PS_SETUP_* bitmap of group capability result. * - * This function can be used to determine group capability based on - * information from P2PS PD exchange and the current state of ongoing - * groups and driver capabilities. - * - * P2PS_SETUP_* bitmap is used as the parameters and return value. + * This function can be used to determine group capability and + * frequencies based on information from P2PS PD exchange and the + * current state of ongoing groups and driver capabilities. */ - u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role); + u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role, + unsigned int *force_freq, + unsigned int *pref_freq); /** * get_pref_freq_list - Get preferred frequency list for an interface @@ -1530,12 +1555,13 @@ enum p2p_probe_req_status { * @ie: Information elements from the Probe Request frame body * @ie_len: Length of ie buffer in octets * @rx_freq: Probe Request frame RX frequency + * @p2p_lo_started: Whether P2P Listen Offload is started * Returns: value indicating the type and status of the probe request */ enum p2p_probe_req_status p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len, - unsigned int rx_freq); + unsigned int rx_freq, int p2p_lo_started); /** * p2p_rx_action - Report received Action frame @@ -1691,6 +1717,12 @@ struct p2p_group_config { int freq; /** + * ip_addr_alloc - Whether IP address allocation within 4-way handshake + * is supported + */ + int ip_addr_alloc; + + /** * cb_ctx - Context to use with callback functions */ void *cb_ctx; @@ -1877,8 +1909,10 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, * @p2p: P2P module context from p2p_init() * @ies: Buffer for writing P2P IE * @dev_id: Device ID to search for or %NULL for any + * @bands: Frequency bands used in the scan (enum wpa_radio_work_band bitmap) */ -void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id); +void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id, + unsigned int bands); /** * p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie @@ -2100,6 +2134,16 @@ int p2p_client_limit_reached(struct p2p_group *group); const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next); /** + * p2p_group_get_client_interface_addr - Get P2P Interface Address of a client in a group + * @group: P2P group context from p2p_group_init() + * @dev_addr: P2P Device Address of the client + * Returns: P2P Interface Address of the client if found or %NULL if no match + * found + */ +const u8 * p2p_group_get_client_interface_addr(struct p2p_group *group, + const u8 *dev_addr); + +/** * p2p_group_get_dev_addr - Get a P2P Device Address of a client in a group * @group: P2P group context from p2p_group_init() * @addr: P2P Interface Address of the client @@ -2241,7 +2285,7 @@ struct wpabuf * wifi_display_encaps(struct wpabuf *subelems); * discovery (p2p_find). A random number of 100 TU units is picked for each * Listen state iteration from [min_disc_int,max_disc_int] range. * - * max_disc_tu can be used to futher limit the discoverable duration. However, + * max_disc_tu can be used to further limit the discoverable duration. However, * it should be noted that use of this parameter is not recommended since it * would not be compliant with the P2P specification. */ @@ -2340,4 +2384,7 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p, int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs, unsigned int *num); +struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p, + unsigned int freq); + #endif /* P2P_H */ diff --git a/freebsd/contrib/wpa/src/radius/radius.h b/freebsd/contrib/wpa/src/radius/radius.h index 5977339e..cd510d2c 100644 --- a/freebsd/contrib/wpa/src/radius/radius.h +++ b/freebsd/contrib/wpa/src/radius/radius.h @@ -1,6 +1,6 @@ /* * RADIUS message processing - * Copyright (c) 2002-2009, 2012, 2014, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2009, 2012, 2014-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -52,6 +52,8 @@ enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_USER_PASSWORD = 2, RADIUS_ATTR_NAS_IP_ADDRESS = 4, RADIUS_ATTR_NAS_PORT = 5, + RADIUS_ATTR_SERVICE_TYPE = 6, + RADIUS_ATTR_FRAMED_IP_ADDRESS = 8, RADIUS_ATTR_FRAMED_MTU = 12, RADIUS_ATTR_REPLY_MESSAGE = 18, RADIUS_ATTR_STATE = 24, @@ -79,6 +81,7 @@ enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53, RADIUS_ATTR_EVENT_TIMESTAMP = 55, + RADIUS_ATTR_EGRESS_VLANID = 56, RADIUS_ATTR_NAS_PORT_TYPE = 61, RADIUS_ATTR_TUNNEL_TYPE = 64, RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65, @@ -108,6 +111,9 @@ enum { RADIUS_ATTR_USER_NAME = 1, }; +/* Service-Type values (RFC 2865, 5.6) */ +#define RADIUS_SERVICE_TYPE_FRAMED 2 + /* Termination-Action */ #define RADIUS_TERMINATION_ACTION_DEFAULT 0 #define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1 @@ -236,7 +242,8 @@ void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret, int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, size_t secret_len); int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, - size_t secret_len); + size_t secret_len, + int require_message_authenticator); struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type, const u8 *data, size_t data_len); struct radius_msg * radius_msg_parse(const u8 *data, size_t len); @@ -250,8 +257,7 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, size_t secret_len, const u8 *req_auth); int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, u8 type); -void radius_msg_make_authenticator(struct radius_msg *msg, - const u8 *data, size_t len); +int radius_msg_make_authenticator(struct radius_msg *msg); struct radius_ms_mppe_keys * radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, const u8 *secret, size_t secret_len); @@ -274,7 +280,8 @@ radius_msg_add_attr_user_password(struct radius_msg *msg, const u8 *data, size_t data_len, const u8 *secret, size_t secret_len); int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len); -int radius_msg_get_vlanid(struct radius_msg *msg); +int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged, + int *tagged); char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen, const u8 *secret, size_t secret_len, struct radius_msg *sent_msg, size_t n); @@ -319,4 +326,6 @@ int radius_copy_class(struct radius_class_data *dst, u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs); +int radius_gen_session_id(u8 *id, size_t len); + #endif /* RADIUS_H */ diff --git a/freebsd/contrib/wpa/src/rsn_supp/pmksa_cache.c b/freebsd/contrib/wpa/src/rsn_supp/pmksa_cache.c index e9bf319a..7f7cbbec 100644 --- a/freebsd/contrib/wpa/src/rsn_supp/pmksa_cache.c +++ b/freebsd/contrib/wpa/src/rsn_supp/pmksa_cache.c @@ -17,7 +17,7 @@ #include "wpa_i.h" #include "pmksa_cache.h" -#ifdef IEEE8021X_EAPOL +#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA) static const int pmksa_cache_max_entries = 32; @@ -111,6 +111,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() * @pmk: The new pairwise master key * @pmk_len: PMK length in bytes, usually PMK_LEN (32) + * @pmkid: Calculated PMKID * @kck: Key confirmation key or %NULL if not yet derived * @kck_len: KCK length in bytes * @aa: Authenticator address @@ -126,13 +127,13 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) */ struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, - const u8 *kck, size_t kck_len, + const u8 *pmkid, const u8 *kck, size_t kck_len, const u8 *aa, const u8 *spa, void *network_ctx, int akmp) { struct rsn_pmksa_cache_entry *entry, *pos, *prev; struct os_reltime now; - if (pmk_len > PMK_LEN) + if (pmk_len > PMK_LEN_MAX) return NULL; if (wpa_key_mgmt_suite_b(akmp) && !kck) @@ -143,7 +144,9 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, return NULL; os_memcpy(entry->pmk, pmk, pmk_len); entry->pmk_len = pmk_len; - if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + if (pmkid) + os_memcpy(entry->pmkid, pmkid, PMKID_LEN); + else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid); else if (wpa_key_mgmt_suite_b(akmp)) rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid); @@ -346,7 +349,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, struct rsn_pmksa_cache_entry *new_entry; new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, - NULL, 0, + NULL, NULL, 0, aa, pmksa->sm->own_addr, old_entry->network_ctx, old_entry->akmp); if (new_entry == NULL) diff --git a/freebsd/contrib/wpa/src/rsn_supp/pmksa_cache.h b/freebsd/contrib/wpa/src/rsn_supp/pmksa_cache.h index f8e040e0..daede6da 100644 --- a/freebsd/contrib/wpa/src/rsn_supp/pmksa_cache.h +++ b/freebsd/contrib/wpa/src/rsn_supp/pmksa_cache.h @@ -15,7 +15,7 @@ struct rsn_pmksa_cache_entry { struct rsn_pmksa_cache_entry *next; u8 pmkid[PMKID_LEN]; - u8 pmk[PMK_LEN]; + u8 pmk[PMK_LEN_MAX]; size_t pmk_len; os_time_t expiration; int akmp; /* WPA_KEY_MGMT_* */ @@ -44,7 +44,7 @@ enum pmksa_free_reason { PMKSA_EXPIRE, }; -#ifdef IEEE8021X_EAPOL +#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA) struct rsn_pmksa_cache * pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, @@ -57,7 +57,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, - const u8 *kck, size_t kck_len, + const u8 *pmkid, const u8 *kck, size_t kck_len, const u8 *aa, const u8 *spa, void *network_ctx, int akmp); struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm); void pmksa_cache_clear_current(struct wpa_sm *sm); @@ -105,7 +105,7 @@ static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, static inline struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, - const u8 *kck, size_t kck_len, + const u8 *pmkid, const u8 *kck, size_t kck_len, const u8 *aa, const u8 *spa, void *network_ctx, int akmp) { return NULL; diff --git a/freebsd/contrib/wpa/src/rsn_supp/preauth.c b/freebsd/contrib/wpa/src/rsn_supp/preauth.c index f6b3cf5c..470f5971 100644 --- a/freebsd/contrib/wpa/src/rsn_supp/preauth.c +++ b/freebsd/contrib/wpa/src/rsn_supp/preauth.c @@ -20,7 +20,7 @@ #include "wpa_i.h" -#ifdef IEEE8021X_EAPOL +#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA) #define PMKID_CANDIDATE_PRIO_SCAN 1000 @@ -95,7 +95,7 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth", pmk, pmk_len); sm->pmk_len = pmk_len; - pmksa_cache_add(sm->pmksa, pmk, pmk_len, + pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, NULL, 0, sm->preauth_bssid, sm->own_addr, sm->network_ctx, @@ -540,4 +540,4 @@ int rsn_preauth_in_progress(struct wpa_sm *sm) return sm->preauth_eapol != NULL; } -#endif /* IEEE8021X_EAPOL */ +#endif /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */ diff --git a/freebsd/contrib/wpa/src/rsn_supp/preauth.h b/freebsd/contrib/wpa/src/rsn_supp/preauth.h index 277f0663..8caf3ee5 100644 --- a/freebsd/contrib/wpa/src/rsn_supp/preauth.h +++ b/freebsd/contrib/wpa/src/rsn_supp/preauth.h @@ -11,7 +11,7 @@ struct wpa_scan_results; -#ifdef IEEE8021X_EAPOL +#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA) void pmksa_candidate_free(struct wpa_sm *sm); int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, @@ -27,7 +27,7 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen, int verbose); int rsn_preauth_in_progress(struct wpa_sm *sm); -#else /* IEEE8021X_EAPOL */ +#else /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */ static inline void pmksa_candidate_free(struct wpa_sm *sm) { @@ -74,6 +74,6 @@ static inline int rsn_preauth_in_progress(struct wpa_sm *sm) return 0; } -#endif /* IEEE8021X_EAPOL */ +#endif /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */ #endif /* PREAUTH_H */ diff --git a/freebsd/contrib/wpa/src/rsn_supp/wpa.c b/freebsd/contrib/wpa/src/rsn_supp/wpa.c index c4181bdf..4ad6bb6a 100644 --- a/freebsd/contrib/wpa/src/rsn_supp/wpa.c +++ b/freebsd/contrib/wpa/src/rsn_supp/wpa.c @@ -3,6 +3,7 @@ /* * WPA Supplicant - WPA state machine and EAPOL-Key processing * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> + * Copyright(c) 2015 Intel Deutschland GmbH * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -25,6 +26,9 @@ #include "peerkey.h" +static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + /** * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message * @sm: Pointer to WPA state machine data from wpa_sm_init() @@ -36,11 +40,13 @@ * @msg: EAPOL-Key message * @msg_len: Length of message * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written + * Returns: >= 0 on success, < 0 on failure */ -void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len, - int ver, const u8 *dest, u16 proto, - u8 *msg, size_t msg_len, u8 *key_mic) +int wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len, + int ver, const u8 *dest, u16 proto, + u8 *msg, size_t msg_len, u8 *key_mic) { + int ret = -1; size_t mic_len = wpa_mic_len(sm->key_mgmt); if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) { @@ -71,10 +77,11 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len, wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, kck_len); wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, mic_len); wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len); - wpa_sm_ether_send(sm, dest, proto, msg, msg_len); + ret = wpa_sm_ether_send(sm, dest, proto, msg, msg_len); eapol_sm_notify_tx_eapol_key(sm->eapol); out: os_free(msg); + return ret; } @@ -126,7 +133,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; key_info = WPA_KEY_INFO_REQUEST | ver; if (sm->ptk_set) - key_info |= WPA_KEY_INFO_MIC; + key_info |= WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; if (error) key_info |= WPA_KEY_INFO_ERROR; if (pairwise) @@ -208,15 +215,21 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, #endif /* CONFIG_IEEE80211R */ } else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) { int res, pmk_len; - pmk_len = PMK_LEN; - res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN); + + if (sm->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + pmk_len = PMK_LEN_SUITE_B_192; + else + pmk_len = PMK_LEN; + res = eapol_sm_get_key(sm->eapol, sm->pmk, pmk_len); if (res) { - /* - * EAP-LEAP is an exception from other EAP methods: it - * uses only 16-byte PMK. - */ - res = eapol_sm_get_key(sm->eapol, sm->pmk, 16); - pmk_len = 16; + if (pmk_len == PMK_LEN) { + /* + * EAP-LEAP is an exception from other EAP + * methods: it uses only 16-byte PMK. + */ + res = eapol_sm_get_key(sm->eapol, sm->pmk, 16); + pmk_len = 16; + } } else { #ifdef CONFIG_IEEE80211R u8 buf[2 * PMK_LEN]; @@ -238,7 +251,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, !wpa_key_mgmt_suite_b(sm->key_mgmt) && !wpa_key_mgmt_ft(sm->key_mgmt)) { sa = pmksa_cache_add(sm->pmksa, - sm->pmk, pmk_len, + sm->pmk, pmk_len, NULL, NULL, 0, src_addr, sm->own_addr, sm->network_ctx, @@ -259,7 +272,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, * much we can do here without knowing what * exactly caused the server to misbehave. */ - wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: PMKID mismatch - authentication server may have derived different MSK?!"); return -1; } @@ -320,7 +333,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, * @wpa_ie: WPA/RSN IE * @wpa_ie_len: Length of the WPA/RSN IE * @ptk: PTK to use for keyed hash and encryption - * Returns: 0 on success, -1 on failure + * Returns: >= 0 on success, < 0 on failure */ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, const struct wpa_eapol_key *key, @@ -353,13 +366,12 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, if (rsn_ie_buf == NULL) return -1; os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len); - res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len, + res = wpa_insert_pmkid(rsn_ie_buf, &wpa_ie_len, sm->pmk_r1_name); if (res < 0) { os_free(rsn_ie_buf); return -1; } - wpa_ie_len += res; if (sm->assoc_resp_ies) { os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies, @@ -411,10 +423,8 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4"); - wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL, - rbuf, rlen, key_mic); - - return 0; + return wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, + ETH_P_EAPOL, rbuf, rlen, key_mic); } @@ -527,7 +537,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, #endif /* CONFIG_P2P */ if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce, - kde, kde_len, ptk)) + kde, kde_len, ptk) < 0) goto failed; os_free(kde_buf); @@ -605,7 +615,6 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, int keylen, rsclen; enum wpa_alg alg; const u8 *key_rsc; - u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; if (sm->ptk.installed) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, @@ -783,12 +792,43 @@ static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm, } +static int wpa_supplicant_rsc_relaxation(const struct wpa_sm *sm, + const u8 *rsc) +{ + int rsclen; + + if (!sm->wpa_rsc_relaxation) + return 0; + + rsclen = wpa_cipher_rsc_len(sm->group_cipher); + + /* + * Try to detect RSC (endian) corruption issue where the AP sends + * the RSC bytes in EAPOL-Key message in the wrong order, both if + * it's actually a 6-byte field (as it should be) and if it treats + * it as an 8-byte field. + * An AP model known to have this bug is the Sapido RB-1632. + */ + if (rsclen == 6 && ((rsc[5] && !rsc[0]) || rsc[6] || rsc[7])) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "RSC %02x%02x%02x%02x%02x%02x%02x%02x is likely bogus, using 0", + rsc[0], rsc[1], rsc[2], rsc[3], + rsc[4], rsc[5], rsc[6], rsc[7]); + + return 1; + } + + return 0; +} + + static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, const struct wpa_eapol_key *key, const u8 *gtk, size_t gtk_len, int key_info) { struct wpa_gtk_data gd; + const u8 *key_rsc; /* * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x @@ -814,11 +854,15 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, os_memcpy(gd.gtk, gtk, gtk_len); gd.gtk_len = gtk_len; + key_rsc = key->key_rsc; + if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc)) + key_rsc = null_rsc; + if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED && (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, gtk_len, gtk_len, &gd.key_rsc_len, &gd.alg) || - wpa_supplicant_install_gtk(sm, &gd, key->key_rsc, 0))) { + wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0))) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Failed to install GTK"); os_memset(&gd, 0, sizeof(gd)); @@ -1055,8 +1099,8 @@ static int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm, if (sm->assoc_resp_ies) { pos = sm->assoc_resp_ies; end = pos + sm->assoc_resp_ies_len; - while (pos + 2 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 2) { + if (2 + pos[1] > end - pos) break; switch (*pos) { case WLAN_EID_MOBILITY_DOMAIN: @@ -1152,7 +1196,7 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm, * @ver: Version bits from EAPOL-Key Key Info * @key_info: Key Info * @ptk: PTK to use for keyed hash and encryption - * Returns: 0 on success, -1 on failure + * Returns: >= 0 on success, < 0 on failure */ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, const struct wpa_eapol_key *key, @@ -1192,10 +1236,8 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, WPA_PUT_BE16(reply->key_data_length, 0); wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4"); - wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL, - rbuf, rlen, key_mic); - - return 0; + return wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, + ETH_P_EAPOL, rbuf, rlen, key_mic); } @@ -1268,7 +1310,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, #endif /* CONFIG_P2P */ if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, - &sm->ptk)) { + &sm->ptk) < 0) { goto failed; } @@ -1313,7 +1355,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) { struct rsn_pmksa_cache_entry *sa; - sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, + sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, NULL, sm->ptk.kck, sm->ptk.kck_len, sm->bssid, sm->own_addr, sm->network_ctx, sm->key_mgmt); @@ -1503,10 +1545,8 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, WPA_PUT_BE16(reply->key_data_length, 0); wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2"); - wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, sm->bssid, - ETH_P_EAPOL, rbuf, rlen, key_mic); - - return 0; + return wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, + sm->bssid, ETH_P_EAPOL, rbuf, rlen, key_mic); } @@ -1519,6 +1559,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, u16 key_info; int rekey, ret; struct wpa_gtk_data gd; + const u8 *key_rsc; if (!sm->msg_3_of_4_ok) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, @@ -1549,13 +1590,17 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, if (ret) goto failed; - if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc, 0) || - wpa_supplicant_send_2_of_2(sm, key, ver, key_info)) + key_rsc = key->key_rsc; + if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc)) + key_rsc = null_rsc; + + if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) || + wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0) goto failed; os_memset(&gd, 0, sizeof(gd)); if (rekey) { - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Group rekeying " + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying " "completed with " MACSTR " [GTK=%s]", MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher)); wpa_sm_cancel_auth_timeout(sm); @@ -1683,14 +1728,14 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, } if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8, key_data, buf)) { - os_free(buf); + bin_clear_free(buf, *key_data_len); wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: AES unwrap failed - " "could not decrypt EAPOL-Key key data"); return -1; } os_memcpy(key_data, buf, *key_data_len); - os_free(buf); + bin_clear_free(buf, *key_data_len); WPA_PUT_BE16(key->key_data_length, *key_data_len); } else { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, @@ -2029,6 +2074,17 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + /* + * Only decrypt the Key Data field if the frame's authenticity + * was verified. When using AES-SIV (FILS), the MIC flag is not + * set, so this check should only be performed if mic_len != 0 + * which is the case in this code branch. + */ + if (!(key_info & WPA_KEY_INFO_MIC)) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Ignore EAPOL-Key with encrypted but unauthenticated data"); + goto out; + } if (wpa_supplicant_decrypt_key_data(sm, key, ver, key_data, &key_data_len)) goto out; @@ -2303,6 +2359,9 @@ void wpa_sm_deinit(struct wpa_sm *sm) #ifdef CONFIG_IEEE80211R os_free(sm->assoc_resp_ies); #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_TESTING_OPTIONS + wpabuf_free(sm->test_assoc_ie); +#endif /* CONFIG_TESTING_OPTIONS */ os_free(sm); } @@ -2410,12 +2469,13 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm) * @sm: Pointer to WPA state machine data from wpa_sm_init() * @pmk: The new PMK * @pmk_len: The length of the new PMK in bytes + * @pmkid: Calculated PMKID * @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK * * Configure the PMK for WPA state machine. */ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len, - const u8 *bssid) + const u8 *pmkid, const u8 *bssid) { if (sm == NULL) return; @@ -2430,7 +2490,7 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len, #endif /* CONFIG_IEEE80211R */ if (bssid) { - pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0, + pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0, bssid, sm->own_addr, sm->network_ctx, sm->key_mgmt); } @@ -2514,6 +2574,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->ssid_len = 0; sm->wpa_ptk_rekey = config->wpa_ptk_rekey; sm->p2p = config->p2p; + sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation; } else { sm->network_ctx = NULL; sm->peerkey_enabled = 0; @@ -2524,6 +2585,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->ssid_len = 0; sm->wpa_ptk_rekey = 0; sm->p2p = 0; + sm->wpa_rsc_relaxation = 0; } } @@ -2711,6 +2773,17 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie, if (sm == NULL) return -1; +#ifdef CONFIG_TESTING_OPTIONS + if (sm->test_assoc_ie) { + wpa_printf(MSG_DEBUG, + "TESTING: Replace association WPA/RSN IE"); + if (*wpa_ie_len < wpabuf_len(sm->test_assoc_ie)) + return -1; + os_memcpy(wpa_ie, wpabuf_head(sm->test_assoc_ie), + wpabuf_len(sm->test_assoc_ie)); + res = wpabuf_len(sm->test_assoc_ie); + } else +#endif /* CONFIG_TESTING_OPTIONS */ res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len); if (res < 0) return -1; @@ -3038,3 +3111,12 @@ void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, } sm->ptk_set = 1; } + + +#ifdef CONFIG_TESTING_OPTIONS +void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf) +{ + wpabuf_free(sm->test_assoc_ie); + sm->test_assoc_ie = buf; +} +#endif /* CONFIG_TESTING_OPTIONS */ diff --git a/freebsd/contrib/wpa/src/rsn_supp/wpa.h b/freebsd/contrib/wpa/src/rsn_supp/wpa.h index e163b701..0b7477f3 100644 --- a/freebsd/contrib/wpa/src/rsn_supp/wpa.h +++ b/freebsd/contrib/wpa/src/rsn_supp/wpa.h @@ -104,6 +104,7 @@ struct rsn_supp_config { size_t ssid_len; int wpa_ptk_rekey; int p2p; + int wpa_rsc_relaxation; }; #ifndef CONFIG_NO_WPA @@ -113,7 +114,7 @@ void wpa_sm_deinit(struct wpa_sm *sm); void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid); void wpa_sm_notify_disassoc(struct wpa_sm *sm); void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len, - const u8 *bssid); + const u8 *pmkid, const u8 *bssid); void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm); void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth); void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx); @@ -180,7 +181,8 @@ static inline void wpa_sm_notify_disassoc(struct wpa_sm *sm) } static inline void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, - size_t pmk_len) + size_t pmk_len, const u8 *pmkid, + const u8 *bssid) { } @@ -320,7 +322,8 @@ static inline void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, } static inline void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck, - const u8 *ptk_kek) + size_t ptk_kck_len, + const u8 *ptk_kek, size_t ptk_kek_len) { } @@ -415,7 +418,12 @@ int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr, u8 oper_class, struct hostapd_freq_params *freq_params); int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr); +#ifdef CONFIG_TDLS_TESTING +extern unsigned int tdls_testing; +#endif /* CONFIG_TDLS_TESTING */ + int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf); +void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf); #endif /* WPA_H */ diff --git a/freebsd/contrib/wpa/src/rsn_supp/wpa_i.h b/freebsd/contrib/wpa/src/rsn_supp/wpa_i.h index 85cc8628..56f88dcd 100644 --- a/freebsd/contrib/wpa/src/rsn_supp/wpa_i.h +++ b/freebsd/contrib/wpa/src/rsn_supp/wpa_i.h @@ -19,7 +19,7 @@ struct wpa_eapol_key; * struct wpa_sm - Internal WPA state machine data */ struct wpa_sm { - u8 pmk[PMK_LEN]; + u8 pmk[PMK_LEN_MAX]; size_t pmk_len; struct wpa_ptk ptk, tptk; int ptk_set, tptk_set; @@ -66,6 +66,7 @@ struct wpa_sm { size_t ssid_len; int wpa_ptk_rekey; int p2p; + int wpa_rsc_relaxation; u8 own_addr[ETH_ALEN]; const char *ifname; @@ -139,6 +140,10 @@ struct wpa_sm { #ifdef CONFIG_P2P u8 p2p_ip_addr[3 * 4]; #endif /* CONFIG_P2P */ + +#ifdef CONFIG_TESTING_OPTIONS + struct wpabuf *test_assoc_ie; +#endif /* CONFIG_TESTING_OPTIONS */ }; @@ -349,16 +354,14 @@ wpa_sm_tdls_disable_channel_switch(struct wpa_sm *sm, const u8 *addr) static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len) { - if (!sm->proactive_key_caching) - return 0; if (!sm->ctx->key_mgmt_set_pmk) return -1; return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len); } -void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len, - int ver, const u8 *dest, u16 proto, - u8 *msg, size_t msg_len, u8 *key_mic); +int wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len, + int ver, const u8 *dest, u16 proto, + u8 *msg, size_t msg_len, u8 *key_mic); int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, const struct wpa_eapol_key *key, int ver, const u8 *nonce, diff --git a/freebsd/contrib/wpa/src/rsn_supp/wpa_ie.c b/freebsd/contrib/wpa/src/rsn_supp/wpa_ie.c index 2a22d7de..4caf9c6b 100644 --- a/freebsd/contrib/wpa/src/rsn_supp/wpa_ie.c +++ b/freebsd/contrib/wpa/src/rsn_supp/wpa_ie.c @@ -380,7 +380,7 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, return 0; } - if (pos + 1 + RSN_SELECTOR_LEN < end && + if (1 + RSN_SELECTOR_LEN < end - pos && pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; @@ -493,13 +493,13 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, int ret = 0; os_memset(ie, 0, sizeof(*ie)); - for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { + for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) { if (pos[0] == 0xdd && ((pos == buf + len - 1) || pos[1] == 0)) { /* Ignore padding */ break; } - if (pos + 2 + pos[1] > end) { + if (2 + pos[1] > end - pos) { wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " "underflow (ie=%d len=%d pos=%d)", pos[0], pos[1], (int) (pos - buf)); diff --git a/freebsd/contrib/wpa/src/tls/tlsv1_client.h b/freebsd/contrib/wpa/src/tls/tlsv1_client.h index a4e25e96..40fa6c7f 100644 --- a/freebsd/contrib/wpa/src/tls/tlsv1_client.h +++ b/freebsd/contrib/wpa/src/tls/tlsv1_client.h @@ -41,7 +41,7 @@ int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn); int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers); int tlsv1_client_set_cred(struct tlsv1_client *conn, struct tlsv1_credentials *cred); -void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled); +void tlsv1_client_set_flags(struct tlsv1_client *conn, unsigned int flags); typedef int (*tlsv1_client_session_ticket_cb) (void *ctx, const u8 *ticket, size_t len, const u8 *client_random, @@ -51,4 +51,12 @@ void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn, tlsv1_client_session_ticket_cb cb, void *ctx); +void tlsv1_client_set_cb(struct tlsv1_client *conn, + void (*event_cb)(void *ctx, enum tls_event ev, + union tls_event_data *data), + void *cb_ctx, + int cert_in_cb); +int tlsv1_client_get_version(struct tlsv1_client *conn, char *buf, + size_t buflen); + #endif /* TLSV1_CLIENT_H */ diff --git a/freebsd/contrib/wpa/src/tls/tlsv1_cred.h b/freebsd/contrib/wpa/src/tls/tlsv1_cred.h index 68fbdc92..716e93c3 100644 --- a/freebsd/contrib/wpa/src/tls/tlsv1_cred.h +++ b/freebsd/contrib/wpa/src/tls/tlsv1_cred.h @@ -14,11 +14,19 @@ struct tlsv1_credentials { struct x509_certificate *cert; struct crypto_private_key *key; + unsigned int cert_probe:1; + unsigned int ca_cert_verify:1; + unsigned int server_cert_only:1; + u8 srv_cert_hash[32]; + /* Diffie-Hellman parameters */ u8 *dh_p; /* prime */ size_t dh_p_len; u8 *dh_g; /* generator */ size_t dh_g_len; + + char *ocsp_stapling_response; + char *ocsp_stapling_response_multi; }; diff --git a/freebsd/contrib/wpa/src/utils/common.c b/freebsd/contrib/wpa/src/utils/common.c index 9665bd3c..4d414bfa 100644 --- a/freebsd/contrib/wpa/src/utils/common.c +++ b/freebsd/contrib/wpa/src/utils/common.c @@ -88,7 +88,7 @@ int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable) return -1; /* check for optional mask */ - if (*r == '\0' || isspace(*r)) { + if (*r == '\0' || isspace((unsigned char) *r)) { /* no mask specified, assume default */ os_memset(mask, 0xff, ETH_ALEN); } else if (maskable && *r == '/') { @@ -500,7 +500,7 @@ void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len) *txt++ = 't'; break; default: - if (data[i] >= 32 && data[i] <= 127) { + if (data[i] >= 32 && data[i] <= 126) { *txt++ = data[i]; } else { txt += os_snprintf(txt, end - txt, "\\x%02x", @@ -699,6 +699,29 @@ int is_hex(const u8 *data, size_t len) } +int has_ctrl_char(const u8 *data, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (data[i] < 32 || data[i] == 127) + return 1; + } + return 0; +} + + +int has_newline(const char *str) +{ + while (*str) { + if (*str == '\n' || *str == '\r') + return 1; + str++; + } + return 0; +} + + size_t merge_byte_arrays(u8 *res, size_t res_len, const u8 *src1, size_t src1_len, const u8 *src2, size_t src2_len) @@ -980,7 +1003,7 @@ int random_mac_addr_keep_oui(u8 *addr) * @delim: a string of delimiters * @last: a pointer to a character following the returned token * It has to be set to NULL for the first call and passed for any - * futher call. + * further call. * Returns: a pointer to token position in str or NULL * * This function is similar to str_token, but it can be used with both @@ -1125,3 +1148,57 @@ int is_ctrl_char(char c) { return c > 0 && c < 32; } + + +/** + * ssid_parse - Parse a string that contains SSID in hex or text format + * @buf: Input NULL terminated string that contains the SSID + * @ssid: Output SSID + * Returns: 0 on success, -1 otherwise + * + * The SSID has to be enclosed in double quotes for the text format or space + * or NULL terminated string of hex digits for the hex format. buf can include + * additional arguments after the SSID. + */ +int ssid_parse(const char *buf, struct wpa_ssid_value *ssid) +{ + char *tmp, *res, *end; + size_t len; + + ssid->ssid_len = 0; + + tmp = os_strdup(buf); + if (!tmp) + return -1; + + if (*tmp != '"') { + end = os_strchr(tmp, ' '); + if (end) + *end = '\0'; + } else { + end = os_strchr(tmp + 1, '"'); + if (!end) { + os_free(tmp); + return -1; + } + + end[1] = '\0'; + } + + res = wpa_config_parse_string(tmp, &len); + if (res && len <= SSID_MAX_LEN) { + ssid->ssid_len = len; + os_memcpy(ssid->ssid, res, len); + } + + os_free(tmp); + os_free(res); + + return ssid->ssid_len ? 0 : -1; +} + + +int str_starts(const char *str, const char *start) +{ + return os_strncmp(str, start, os_strlen(start)) == 0; +} diff --git a/freebsd/contrib/wpa/src/utils/common.h b/freebsd/contrib/wpa/src/utils/common.h index 0b9cc3d8..77856774 100644 --- a/freebsd/contrib/wpa/src/utils/common.h +++ b/freebsd/contrib/wpa/src/utils/common.h @@ -313,6 +313,9 @@ static inline void WPA_PUT_LE64(u8 *a, u64 val) #ifndef ETH_P_ALL #define ETH_P_ALL 0x0003 #endif +#ifndef ETH_P_IP +#define ETH_P_IP 0x0800 +#endif #ifndef ETH_P_80211_ENCAP #define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */ #endif @@ -416,6 +419,7 @@ void perror(const char *s); */ #ifdef __CHECKER__ #define __force __attribute__((force)) +#undef __bitwise #define __bitwise __attribute__((bitwise)) #else #define __force @@ -445,6 +449,13 @@ typedef u64 __bitwise le64; #endif /* __GNUC__ */ #endif /* __must_check */ +#define SSID_MAX_LEN 32 + +struct wpa_ssid_value { + u8 ssid[SSID_MAX_LEN]; + size_t ssid_len; +}; + int hwaddr_aton(const char *txt, u8 *addr); int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable); int hwaddr_compact_aton(const char *txt, u8 *addr); @@ -461,6 +472,7 @@ int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len); int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask); +int ssid_parse(const char *buf, struct wpa_ssid_value *ssid); #ifdef CONFIG_NATIVE_WINDOWS void wpa_unicode2ascii_inplace(TCHAR *str); @@ -477,6 +489,8 @@ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); char * wpa_config_parse_string(const char *value, size_t *len); int is_hex(const u8 *data, size_t len); +int has_ctrl_char(const u8 *data, size_t len); +int has_newline(const char *str); size_t merge_byte_arrays(u8 *res, size_t res_len, const u8 *src1, size_t src1_len, const u8 *src2, size_t src2_len); @@ -536,6 +550,8 @@ size_t utf8_unescape(const char *inp, size_t in_size, char *outp, size_t out_size); int is_ctrl_char(char c); +int str_starts(const char *str, const char *start); + /* * gcc 4.4 ends up generating strict-aliasing warnings about some very common diff --git a/freebsd/contrib/wpa/src/utils/eloop.c b/freebsd/contrib/wpa/src/utils/eloop.c index 5b1cc862..2ec86ff6 100644 --- a/freebsd/contrib/wpa/src/utils/eloop.c +++ b/freebsd/contrib/wpa/src/utils/eloop.c @@ -20,7 +20,12 @@ #error Do not define both of poll and epoll #endif -#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) +#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE) +#error Do not define both of poll and kqueue +#endif + +#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \ + !defined(CONFIG_ELOOP_KQUEUE) #define CONFIG_ELOOP_SELECT #endif @@ -32,6 +37,10 @@ #include <sys/epoll.h> #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE +#include <sys/event.h> +#endif /* CONFIG_ELOOP_KQUEUE */ + struct eloop_sock { int sock; void *eloop_data; @@ -77,13 +86,20 @@ struct eloop_data { struct pollfd *pollfds; struct pollfd **pollfds_map; #endif /* CONFIG_ELOOP_POLL */ +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) + int max_fd; + struct eloop_sock *fd_table; +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ #ifdef CONFIG_ELOOP_EPOLL int epollfd; int epoll_max_event_num; - int epoll_max_fd; - struct eloop_sock *epoll_table; struct epoll_event *epoll_events; #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + int kqueuefd; + int kqueue_nevents; + struct kevent *kqueue_events; +#endif /* CONFIG_ELOOP_KQUEUE */ struct eloop_sock_table readers; struct eloop_sock_table writers; struct eloop_sock_table exceptions; @@ -151,14 +167,24 @@ int eloop_init(void) #ifdef CONFIG_ELOOP_EPOLL eloop.epollfd = epoll_create1(0); if (eloop.epollfd < 0) { - wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s\n", + wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s", + __func__, strerror(errno)); + return -1; + } +#endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + eloop.kqueuefd = kqueue(); + if (eloop.kqueuefd < 0) { + wpa_printf(MSG_ERROR, "%s: kqueue failed: %s", __func__, strerror(errno)); return -1; } +#endif /* CONFIG_ELOOP_KQUEUE */ +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) eloop.readers.type = EVENT_TYPE_READ; eloop.writers.type = EVENT_TYPE_WRITE; eloop.exceptions.type = EVENT_TYPE_EXCEPTION; -#endif /* CONFIG_ELOOP_EPOLL */ +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ #ifdef WPA_TRACE signal(SIGSEGV, eloop_sigsegv_handler); #endif /* WPA_TRACE */ @@ -166,15 +192,80 @@ int eloop_init(void) } +#ifdef CONFIG_ELOOP_EPOLL +static int eloop_sock_queue(int sock, eloop_event_type type) +{ + struct epoll_event ev; + + os_memset(&ev, 0, sizeof(ev)); + switch (type) { + case EVENT_TYPE_READ: + ev.events = EPOLLIN; + break; + case EVENT_TYPE_WRITE: + ev.events = EPOLLOUT; + break; + /* + * Exceptions are always checked when using epoll, but I suppose it's + * possible that someone registered a socket *only* for exception + * handling. + */ + case EVENT_TYPE_EXCEPTION: + ev.events = EPOLLERR | EPOLLHUP; + break; + } + ev.data.fd = sock; + if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) { + wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s", + __func__, sock, strerror(errno)); + return -1; + } + return 0; +} +#endif /* CONFIG_ELOOP_EPOLL */ + + +#ifdef CONFIG_ELOOP_KQUEUE +static int eloop_sock_queue(int sock, eloop_event_type type) +{ + int filter; + struct kevent ke; + + switch (type) { + case EVENT_TYPE_READ: + filter = EVFILT_READ; + break; + case EVENT_TYPE_WRITE: + filter = EVFILT_WRITE; + break; + default: + filter = 0; + } + EV_SET(&ke, sock, filter, EV_ADD, 0, 0, 0); + if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) { + wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s", + __func__, sock, strerror(errno)); + return -1; + } + return 0; +} +#endif /* CONFIG_ELOOP_KQUEUE */ + + static int eloop_sock_table_add_sock(struct eloop_sock_table *table, int sock, eloop_sock_handler handler, void *eloop_data, void *user_data) { #ifdef CONFIG_ELOOP_EPOLL + struct epoll_event *temp_events; +#endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + struct kevent *temp_events; +#endif /* CONFIG_ELOOP_EPOLL */ +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) struct eloop_sock *temp_table; - struct epoll_event ev, *temp_events; int next; -#endif /* CONFIG_ELOOP_EPOLL */ +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ struct eloop_sock *tmp; int new_max_sock; @@ -210,26 +301,28 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, eloop.pollfds = n; } #endif /* CONFIG_ELOOP_POLL */ -#ifdef CONFIG_ELOOP_EPOLL - if (new_max_sock >= eloop.epoll_max_fd) { - next = eloop.epoll_max_fd == 0 ? 16 : eloop.epoll_max_fd * 2; - temp_table = os_realloc_array(eloop.epoll_table, next, +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) + if (new_max_sock >= eloop.max_fd) { + next = eloop.max_fd == 0 ? 16 : eloop.max_fd * 2; + temp_table = os_realloc_array(eloop.fd_table, next, sizeof(struct eloop_sock)); if (temp_table == NULL) return -1; - eloop.epoll_max_fd = next; - eloop.epoll_table = temp_table; + eloop.max_fd = next; + eloop.fd_table = temp_table; } +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ +#ifdef CONFIG_ELOOP_EPOLL if (eloop.count + 1 > eloop.epoll_max_event_num) { next = eloop.epoll_max_event_num == 0 ? 8 : eloop.epoll_max_event_num * 2; temp_events = os_realloc_array(eloop.epoll_events, next, sizeof(struct epoll_event)); if (temp_events == NULL) { - wpa_printf(MSG_ERROR, "%s: malloc for epoll failed. " - "%s\n", __func__, strerror(errno)); + wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s", + __func__, strerror(errno)); return -1; } @@ -237,6 +330,22 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, eloop.epoll_events = temp_events; } #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + if (eloop.count + 1 > eloop.kqueue_nevents) { + next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2; + temp_events = os_malloc(next * sizeof(*temp_events)); + if (!temp_events) { + wpa_printf(MSG_ERROR, + "%s: malloc for kqueue failed: %s", + __func__, strerror(errno)); + return -1; + } + + os_free(eloop.kqueue_events); + eloop.kqueue_events = temp_events; + eloop.kqueue_nevents = next; + } +#endif /* CONFIG_ELOOP_KQUEUE */ eloop_trace_sock_remove_ref(table); tmp = os_realloc_array(table->table, table->count + 1, @@ -258,33 +367,12 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, table->changed = 1; eloop_trace_sock_add_ref(table); -#ifdef CONFIG_ELOOP_EPOLL - os_memset(&ev, 0, sizeof(ev)); - switch (table->type) { - case EVENT_TYPE_READ: - ev.events = EPOLLIN; - break; - case EVENT_TYPE_WRITE: - ev.events = EPOLLOUT; - break; - /* - * Exceptions are always checked when using epoll, but I suppose it's - * possible that someone registered a socket *only* for exception - * handling. - */ - case EVENT_TYPE_EXCEPTION: - ev.events = EPOLLERR | EPOLLHUP; - break; - } - ev.data.fd = sock; - if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) { - wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d " - "failed. %s\n", __func__, sock, strerror(errno)); +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) + if (eloop_sock_queue(sock, table->type) < 0) return -1; - } - os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1], + os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1], sizeof(struct eloop_sock)); -#endif /* CONFIG_ELOOP_EPOLL */ +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ return 0; } @@ -292,6 +380,9 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, int sock) { +#ifdef CONFIG_ELOOP_KQUEUE + struct kevent ke; +#endif /* CONFIG_ELOOP_KQUEUE */ int i; if (table == NULL || table->table == NULL || table->count == 0) @@ -315,12 +406,21 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, eloop_trace_sock_add_ref(table); #ifdef CONFIG_ELOOP_EPOLL if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) { - wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d " - "failed. %s\n", __func__, sock, strerror(errno)); + wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s", + __func__, sock, strerror(errno)); return; } - os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock)); + os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock)); #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + EV_SET(&ke, sock, 0, EV_DELETE, 0, 0, 0); + if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) { + wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s", + __func__, sock, strerror(errno)); + return; + } + os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock)); +#endif /* CONFIG_ELOOP_KQUEUE */ } @@ -513,7 +613,7 @@ static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds) int i; for (i = 0; i < nfds; i++) { - table = &eloop.epoll_table[events[i].data.fd]; + table = &eloop.fd_table[events[i].data.fd]; if (table->handler == NULL) continue; table->handler(table->sock, table->eloop_data, @@ -527,6 +627,67 @@ static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds) #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + +static void eloop_sock_table_dispatch(struct kevent *events, int nfds) +{ + struct eloop_sock *table; + int i; + + for (i = 0; i < nfds; i++) { + table = &eloop.fd_table[events[i].ident]; + if (table->handler == NULL) + continue; + table->handler(table->sock, table->eloop_data, + table->user_data); + if (eloop.readers.changed || + eloop.writers.changed || + eloop.exceptions.changed) + break; + } +} + + +static int eloop_sock_table_requeue(struct eloop_sock_table *table) +{ + int i, r; + + r = 0; + for (i = 0; i < table->count && table->table; i++) { + if (eloop_sock_queue(table->table[i].sock, table->type) == -1) + r = -1; + } + return r; +} + +#endif /* CONFIG_ELOOP_KQUEUE */ + + +int eloop_sock_requeue(void) +{ + int r = 0; + +#ifdef CONFIG_ELOOP_KQUEUE + close(eloop.kqueuefd); + eloop.kqueuefd = kqueue(); + if (eloop.kqueuefd < 0) { + wpa_printf(MSG_ERROR, "%s: kqueue failed: %s", + __func__, strerror(errno)); + return -1; + } + + if (eloop_sock_table_requeue(&eloop.readers) < 0) + r = -1; + if (eloop_sock_table_requeue(&eloop.writers) < 0) + r = -1; + if (eloop_sock_table_requeue(&eloop.exceptions) < 0) + r = -1; +#endif /* CONFIG_ELOOP_KQUEUE */ + + return r; +} + + static void eloop_sock_table_destroy(struct eloop_sock_table *table) { if (table) { @@ -907,6 +1068,9 @@ void eloop_run(void) #ifdef CONFIG_ELOOP_EPOLL int timeout_ms = -1; #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + struct timespec ts; +#endif /* CONFIG_ELOOP_KQUEUE */ int res; struct os_reltime tv, now; @@ -951,6 +1115,10 @@ void eloop_run(void) _tv.tv_sec = tv.sec; _tv.tv_usec = tv.usec; #endif /* CONFIG_ELOOP_SELECT */ +#ifdef CONFIG_ELOOP_KQUEUE + ts.tv_sec = tv.sec; + ts.tv_nsec = tv.usec * 1000L; +#endif /* CONFIG_ELOOP_KQUEUE */ } #ifdef CONFIG_ELOOP_POLL @@ -976,6 +1144,15 @@ void eloop_run(void) eloop.count, timeout_ms); } #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + if (eloop.count == 0) { + res = 0; + } else { + res = kevent(eloop.kqueuefd, NULL, 0, + eloop.kqueue_events, eloop.kqueue_nevents, + timeout ? &ts : NULL); + } +#endif /* CONFIG_ELOOP_KQUEUE */ if (res < 0 && errno != EINTR && errno != 0) { wpa_printf(MSG_ERROR, "eloop: %s: %s", #ifdef CONFIG_ELOOP_POLL @@ -987,6 +1164,10 @@ void eloop_run(void) #ifdef CONFIG_ELOOP_EPOLL "epoll" #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + "kqueue" +#endif /* CONFIG_ELOOP_EKQUEUE */ + , strerror(errno)); goto out; } @@ -997,6 +1178,7 @@ void eloop_run(void) eloop_process_pending_signals(); + /* check if some registered timeouts have occurred */ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, list); @@ -1042,6 +1224,9 @@ void eloop_run(void) #ifdef CONFIG_ELOOP_EPOLL eloop_sock_table_dispatch(eloop.epoll_events, res); #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + eloop_sock_table_dispatch(eloop.kqueue_events, res); +#endif /* CONFIG_ELOOP_KQUEUE */ } eloop.terminate = 0; @@ -1094,11 +1279,17 @@ void eloop_destroy(void) os_free(eloop.pollfds); os_free(eloop.pollfds_map); #endif /* CONFIG_ELOOP_POLL */ +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) + os_free(eloop.fd_table); +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ #ifdef CONFIG_ELOOP_EPOLL - os_free(eloop.epoll_table); os_free(eloop.epoll_events); close(eloop.epollfd); #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + os_free(eloop.kqueue_events); + close(eloop.kqueuefd); +#endif /* CONFIG_ELOOP_KQUEUE */ } @@ -1137,6 +1328,17 @@ void eloop_wait_for_read_sock(int sock) FD_SET(sock, &rfds); select(sock + 1, &rfds, NULL, NULL, NULL); #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */ +#ifdef CONFIG_ELOOP_KQUEUE + int kfd; + struct kevent ke1, ke2; + + kfd = kqueue(); + if (kfd == -1) + return; + EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0); + kevent(kfd, &ke1, 1, &ke2, 1, NULL); + close(kfd); +#endif /* CONFIG_ELOOP_KQUEUE */ } #ifdef CONFIG_ELOOP_SELECT diff --git a/freebsd/contrib/wpa/src/utils/eloop.h b/freebsd/contrib/wpa/src/utils/eloop.h index 07b8c0dc..97af16f0 100644 --- a/freebsd/contrib/wpa/src/utils/eloop.h +++ b/freebsd/contrib/wpa/src/utils/eloop.h @@ -313,6 +313,14 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler, void *user_data); /** + * eloop_sock_requeue - Requeue sockets + * + * Requeue sockets after forking because some implementations require this, + * such as epoll and kqueue. + */ +int eloop_sock_requeue(void); + +/** * eloop_run - Start the event loop * * Start the event loop and continue running as long as there are any diff --git a/freebsd/contrib/wpa/src/utils/module_tests.h b/freebsd/contrib/wpa/src/utils/module_tests.h new file mode 100644 index 00000000..3bfe4ad0 --- /dev/null +++ b/freebsd/contrib/wpa/src/utils/module_tests.h @@ -0,0 +1,20 @@ +/* + * Module tests + * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef MODULE_TESTS_H +#define MODULE_TESTS_H + +int wpas_module_tests(void); +int hapd_module_tests(void); + +int utils_module_tests(void); +int wps_module_tests(void); +int common_module_tests(void); +int crypto_module_tests(void); + +#endif /* MODULE_TESTS_H */ diff --git a/freebsd/contrib/wpa/src/utils/os.h b/freebsd/contrib/wpa/src/utils/os.h index 9e496fb6..e8f0b792 100644 --- a/freebsd/contrib/wpa/src/utils/os.h +++ b/freebsd/contrib/wpa/src/utils/os.h @@ -657,6 +657,10 @@ int os_exec(const char *program, const char *arg, int wait_completion); #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) #define TEST_FAIL() testing_test_fail() int testing_test_fail(void); +extern char wpa_trace_fail_func[256]; +extern unsigned int wpa_trace_fail_after; +extern char wpa_trace_test_fail_func[256]; +extern unsigned int wpa_trace_test_fail_after; #else #define TEST_FAIL() 0 #endif diff --git a/freebsd/contrib/wpa/src/utils/os_unix.c b/freebsd/contrib/wpa/src/utils/os_unix.c index 1c960e51..b5879dc8 100644 --- a/freebsd/contrib/wpa/src/utils/os_unix.c +++ b/freebsd/contrib/wpa/src/utils/os_unix.c @@ -411,6 +411,7 @@ void os_program_deinit(void) if (total) wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", (unsigned long) total); + wpa_trace_deinit(); #endif /* WPA_TRACE */ } @@ -473,11 +474,7 @@ char * os_readfile(const char *name, size_t *len) int os_file_exists(const char *fname) { - FILE *f = fopen(fname, "rb"); - if (f == NULL) - return 0; - fclose(f); - return 1; + return access(fname, F_OK) == 0; } diff --git a/freebsd/contrib/wpa/src/utils/platform.h b/freebsd/contrib/wpa/src/utils/platform.h index 46cfe785..813987eb 100644 --- a/freebsd/contrib/wpa/src/utils/platform.h +++ b/freebsd/contrib/wpa/src/utils/platform.h @@ -15,7 +15,7 @@ \ __ptr->__val; \ }) -#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((uint16_t *)(p))) -#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((uint32_t *)(p))) +#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((le16 *)(p))) +#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((le32 *)(p))) #endif /* PLATFORM_H */ diff --git a/freebsd/contrib/wpa/src/utils/trace.h b/freebsd/contrib/wpa/src/utils/trace.h index 43ed86c1..d1636de0 100644 --- a/freebsd/contrib/wpa/src/utils/trace.h +++ b/freebsd/contrib/wpa/src/utils/trace.h @@ -66,4 +66,6 @@ void wpa_trace_dump_funcname(const char *title, void *pc); #endif /* WPA_TRACE_BFD */ +void wpa_trace_deinit(void); + #endif /* TRACE_H */ diff --git a/freebsd/contrib/wpa/src/utils/wpa_debug.c b/freebsd/contrib/wpa/src/utils/wpa_debug.c index 1b725ad5..68100490 100644 --- a/freebsd/contrib/wpa/src/utils/wpa_debug.c +++ b/freebsd/contrib/wpa/src/utils/wpa_debug.c @@ -150,7 +150,7 @@ int wpa_debug_open_linux_tracing(void) strtok_r(line, " ", &tmp2); tmp_path = strtok_r(NULL, " ", &tmp2); fstype = strtok_r(NULL, " ", &tmp2); - if (strcmp(fstype, "debugfs") == 0) { + if (fstype && strcmp(fstype, "debugfs") == 0) { path = tmp_path; break; } @@ -519,16 +519,18 @@ int wpa_debug_reopen_file(void) { #ifdef CONFIG_DEBUG_FILE int rv; - if (last_path) { - char *tmp = os_strdup(last_path); - wpa_debug_close_file(); - rv = wpa_debug_open_file(tmp); - os_free(tmp); - } else { - wpa_printf(MSG_ERROR, "Last-path was not set, cannot " - "re-open log file."); - rv = -1; - } + char *tmp; + + if (!last_path) + return 0; /* logfile not used */ + + tmp = os_strdup(last_path); + if (!tmp) + return -1; + + wpa_debug_close_file(); + rv = wpa_debug_open_file(tmp); + os_free(tmp); return rv; #else /* CONFIG_DEBUG_FILE */ return 0; diff --git a/freebsd/contrib/wpa/src/utils/wpabuf.c b/freebsd/contrib/wpa/src/utils/wpabuf.c index c6e22aeb..26e2e8bb 100644 --- a/freebsd/contrib/wpa/src/utils/wpabuf.c +++ b/freebsd/contrib/wpa/src/utils/wpabuf.c @@ -312,3 +312,33 @@ void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) wpabuf_overflow(buf, res); buf->used += res; } + + +/** + * wpabuf_parse_bin - Parse a null terminated string of binary data to a wpabuf + * @buf: Buffer with null terminated string (hexdump) of binary data + * Returns: wpabuf or %NULL on failure + * + * The string len must be a multiple of two and contain only hexadecimal digits. + */ +struct wpabuf * wpabuf_parse_bin(const char *buf) +{ + size_t len; + struct wpabuf *ret; + + len = os_strlen(buf); + if (len & 0x01) + return NULL; + len /= 2; + + ret = wpabuf_alloc(len); + if (ret == NULL) + return NULL; + + if (hexstr2bin(buf, wpabuf_put(ret, len), len)) { + wpabuf_free(ret); + return NULL; + } + + return ret; +} diff --git a/freebsd/contrib/wpa/src/utils/wpabuf.h b/freebsd/contrib/wpa/src/utils/wpabuf.h index c3ef1bae..01da41b3 100644 --- a/freebsd/contrib/wpa/src/utils/wpabuf.h +++ b/freebsd/contrib/wpa/src/utils/wpabuf.h @@ -37,6 +37,7 @@ 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); +struct wpabuf * wpabuf_parse_bin(const char *buf); /** @@ -81,7 +82,7 @@ static inline const void * wpabuf_head(const struct wpabuf *buf) static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) { - return wpabuf_head(buf); + return (const u8 *) wpabuf_head(buf); } /** @@ -96,42 +97,42 @@ static inline void * wpabuf_mhead(struct wpabuf *buf) static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) { - return wpabuf_mhead(buf); + return (u8 *) wpabuf_mhead(buf); } static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) { - u8 *pos = wpabuf_put(buf, 1); + u8 *pos = (u8 *) wpabuf_put(buf, 1); *pos = data; } static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) { - u8 *pos = wpabuf_put(buf, 2); + u8 *pos = (u8 *) 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); + u8 *pos = (u8 *) 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); + u8 *pos = (u8 *) 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); + u8 *pos = (u8 *) 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); + u8 *pos = (u8 *) wpabuf_put(buf, 4); WPA_PUT_BE32(pos, data); } diff --git a/freebsd/contrib/wpa/src/wps/wps.c b/freebsd/contrib/wpa/src/wps/wps.c index fb6d8f65..c0caca91 100644 --- a/freebsd/contrib/wpa/src/wps/wps.c +++ b/freebsd/contrib/wpa/src/wps/wps.c @@ -21,6 +21,10 @@ int wps_version_number = 0x20; int wps_testing_dummy_cred = 0; int wps_corrupt_pkhash = 0; +int wps_force_auth_types_in_use = 0; +u16 wps_force_auth_types = 0; +int wps_force_encr_types_in_use = 0; +u16 wps_force_encr_types = 0; #endif /* CONFIG_WPS_TESTING */ @@ -172,7 +176,7 @@ void wps_deinit(struct wps_data *data) } else if (data->registrar) wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e); - wpabuf_free(data->dh_privkey); + wpabuf_clear_free(data->dh_privkey); wpabuf_free(data->dh_pubkey_e); wpabuf_free(data->dh_pubkey_r); wpabuf_free(data->last_msg); diff --git a/freebsd/contrib/wpa/src/wps/wps.h b/freebsd/contrib/wpa/src/wps/wps.h index 2c91d167..2505d2d9 100644 --- a/freebsd/contrib/wpa/src/wps/wps.h +++ b/freebsd/contrib/wpa/src/wps/wps.h @@ -1,6 +1,6 @@ /* * Wi-Fi Protected Setup - * Copyright (c) 2007-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2007-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -664,6 +664,16 @@ struct wps_context { u16 encr_types; /** + * encr_types_rsn - Enabled encryption types for RSN (WPS_ENCR_*) + */ + u16 encr_types_rsn; + + /** + * encr_types_wpa - Enabled encryption types for WPA (WPS_ENCR_*) + */ + u16 encr_types_wpa; + + /** * auth_types - Authentication types (bit field of WPS_AUTH_*) */ u16 auth_types; @@ -827,7 +837,7 @@ int wps_build_credential_wrap(struct wpabuf *msg, unsigned int wps_pin_checksum(unsigned int pin); unsigned int wps_pin_valid(unsigned int pin); -unsigned int wps_generate_pin(void); +int wps_generate_pin(unsigned int *pin); int wps_pin_str_valid(const char *pin); void wps_free_pending_msgs(struct upnp_pending_message *msgs); diff --git a/freebsd/contrib/wpa/src/wps/wps_attr_build.c b/freebsd/contrib/wpa/src/wps/wps_attr_build.c index 742e082c..e7083388 100644 --- a/freebsd/contrib/wpa/src/wps/wps_attr_build.c +++ b/freebsd/contrib/wpa/src/wps/wps_attr_build.c @@ -2,7 +2,7 @@ /* * Wi-Fi Protected Setup - attribute building - * Copyright (c) 2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -22,10 +22,10 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg) { - struct wpabuf *pubkey; + struct wpabuf *pubkey = NULL; wpa_printf(MSG_DEBUG, "WPS: * Public Key"); - wpabuf_free(wps->dh_privkey); + wpabuf_clear_free(wps->dh_privkey); wps->dh_privkey = NULL; if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey && wps->wps->dh_ctx) { @@ -300,7 +300,16 @@ int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg) auth_types &= ~WPS_AUTH_WPA; auth_types &= ~WPS_AUTH_WPA2; auth_types &= ~WPS_AUTH_SHARED; - wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags"); +#ifdef CONFIG_WPS_TESTING + if (wps_force_auth_types_in_use) { + wpa_printf(MSG_DEBUG, + "WPS: Testing - replace auth type 0x%x with 0x%x", + auth_types, wps_force_auth_types); + auth_types = wps_force_auth_types; + } +#endif /* CONFIG_WPS_TESTING */ + wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags (0x%x)", + auth_types); wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS); wpabuf_put_be16(msg, 2); wpabuf_put_be16(msg, auth_types); @@ -312,7 +321,16 @@ int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg) { u16 encr_types = WPS_ENCR_TYPES; encr_types &= ~WPS_ENCR_WEP; - wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags"); +#ifdef CONFIG_WPS_TESTING + if (wps_force_encr_types_in_use) { + wpa_printf(MSG_DEBUG, + "WPS: Testing - replace encr type 0x%x with 0x%x", + encr_types, wps_force_encr_types); + encr_types = wps_force_encr_types; + } +#endif /* CONFIG_WPS_TESTING */ + wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags (0x%x)", + encr_types); wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS); wpabuf_put_be16(msg, 2); wpabuf_put_be16(msg, encr_types); @@ -397,7 +415,8 @@ int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id, dev_pw_id); addr[0] = wpabuf_head(pubkey); hash_len = wpabuf_len(pubkey); - sha256_vector(1, addr, &hash_len, pubkey_hash); + if (sha256_vector(1, addr, &hash_len, pubkey_hash) < 0) + return -1; #ifdef CONFIG_WPS_TESTING if (wps_corrupt_pkhash) { wpa_hexdump(MSG_DEBUG, "WPS: Real Public Key Hash", diff --git a/freebsd/contrib/wpa/src/wps/wps_attr_parse.c b/freebsd/contrib/wpa/src/wps/wps_attr_parse.c index 748fe0ac..edcfb58b 100644 --- a/freebsd/contrib/wpa/src/wps/wps_attr_parse.c +++ b/freebsd/contrib/wpa/src/wps/wps_attr_parse.c @@ -85,10 +85,10 @@ static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos, const u8 *end = pos + len; u8 id, elen; - while (pos + 2 <= end) { + while (end - pos >= 2) { id = *pos++; elen = *pos++; - if (pos + elen > end) + if (elen > end - pos) break; if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0) return -1; diff --git a/freebsd/contrib/wpa/src/wps/wps_attr_process.c b/freebsd/contrib/wpa/src/wps/wps_attr_process.c index 329649df..bf04d784 100644 --- a/freebsd/contrib/wpa/src/wps/wps_attr_process.c +++ b/freebsd/contrib/wpa/src/wps/wps_attr_process.c @@ -231,6 +231,16 @@ static int wps_workaround_cred_key(struct wps_credential *cred) cred->key_len--; #endif /* CONFIG_WPS_STRICT */ } + + + if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) && + (cred->key_len < 8 || has_ctrl_char(cred->key, cred->key_len))) { + wpa_printf(MSG_INFO, "WPS: Reject credential with invalid WPA/WPA2-Personal passphrase"); + wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key", + cred->key, cred->key_len); + return -1; + } + return 0; } diff --git a/freebsd/contrib/wpa/src/wps/wps_common.c b/freebsd/contrib/wpa/src/wps/wps_common.c index b6c83892..d7ac00b7 100644 --- a/freebsd/contrib/wpa/src/wps/wps_common.c +++ b/freebsd/contrib/wpa/src/wps/wps_common.c @@ -92,7 +92,7 @@ int wps_derive_keys(struct wps_data *wps) } /* Own DH private key is not needed anymore */ - wpabuf_free(wps->dh_privkey); + wpabuf_clear_free(wps->dh_privkey); wps->dh_privkey = NULL; wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared); @@ -102,7 +102,7 @@ int wps_derive_keys(struct wps_data *wps) 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); + wpabuf_clear_free(dh_shared); /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */ addr[0] = wps->nonce_e; @@ -131,23 +131,26 @@ 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) +int 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); + if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, + (dev_passwd_len + 1) / 2, hash) < 0) + return -1; 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); + if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, + dev_passwd + (dev_passwd_len + 1) / 2, + dev_passwd_len / 2, hash) < 0) + return -1; 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); + return 0; } @@ -175,7 +178,7 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, 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); + wpabuf_clear_free(decrypted); return NULL; } @@ -186,14 +189,14 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, pad = *pos; if (pad > wpabuf_len(decrypted)) { wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value"); - wpabuf_free(decrypted); + wpabuf_clear_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); + wpabuf_clear_free(decrypted); return NULL; } } @@ -237,20 +240,18 @@ unsigned int wps_pin_valid(unsigned int pin) * wps_generate_pin - Generate a random PIN * Returns: Eight digit PIN (i.e., including the checksum digit) */ -unsigned int wps_generate_pin(void) +int wps_generate_pin(unsigned int *pin) { 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 = os_random() ^ now.sec ^ now.usec; - } + if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) + return -1; val %= 10000000; /* Append checksum digit */ - return val * 10 + wps_pin_checksum(val); + *pin = val * 10 + wps_pin_checksum(val); + return 0; } @@ -377,7 +378,7 @@ struct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band, wps_build_mac_addr(plain, wps->dev.mac_addr) || wps_build_wfa_ext(plain, 0, NULL, 0)) { os_free(data.new_psk); - wpabuf_free(plain); + wpabuf_clear_free(plain); return NULL; } @@ -425,7 +426,7 @@ struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id, wps_build_wfa_ext(data, 0, NULL, 0)) { wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password " "token"); - wpabuf_free(data); + wpabuf_clear_free(data); return NULL; } @@ -662,7 +663,7 @@ int wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey) wpabuf_free(*pubkey); *pubkey = pub; - wpabuf_free(*privkey); + wpabuf_clear_free(*privkey); *privkey = priv; return 0; @@ -693,7 +694,7 @@ struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey, } *id = 0x10 + val % 0xfff0; - wpabuf_free(*dev_pw); + wpabuf_clear_free(*dev_pw); *dev_pw = pw; return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw); diff --git a/freebsd/contrib/wpa/src/wps/wps_defs.h b/freebsd/contrib/wpa/src/wps/wps_defs.h index a23b979d..301864da 100644 --- a/freebsd/contrib/wpa/src/wps/wps_defs.h +++ b/freebsd/contrib/wpa/src/wps/wps_defs.h @@ -14,6 +14,10 @@ extern int wps_version_number; extern int wps_testing_dummy_cred; extern int wps_corrupt_pkhash; +extern int wps_force_auth_types_in_use; +extern u16 wps_force_auth_types; +extern int wps_force_encr_types_in_use; +extern u16 wps_force_encr_types; #define WPS_VERSION wps_version_number #else /* CONFIG_WPS_TESTING */ diff --git a/freebsd/contrib/wpa/src/wps/wps_enrollee.c b/freebsd/contrib/wpa/src/wps/wps_enrollee.c index e2cfa571..2260b506 100644 --- a/freebsd/contrib/wpa/src/wps/wps_enrollee.c +++ b/freebsd/contrib/wpa/src/wps/wps_enrollee.c @@ -175,7 +175,8 @@ static struct wpabuf * wps_build_m3(struct wps_data *wps) wpa_printf(MSG_DEBUG, "WPS: No Device Password available"); return NULL; } - wps_derive_psk(wps, wps->dev_password, wps->dev_password_len); + if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0) + return NULL; if (wps->wps->ap && random_pool_ready() != 1) { wpa_printf(MSG_INFO, @@ -226,11 +227,11 @@ static struct wpabuf * wps_build_m5(struct wps_data *wps) wps_build_encr_settings(wps, msg, plain) || wps_build_wfa_ext(msg, 0, NULL, 0) || wps_build_authenticator(wps, msg)) { - wpabuf_free(plain); + wpabuf_clear_free(plain); wpabuf_free(msg); return NULL; } - wpabuf_free(plain); + wpabuf_clear_free(plain); wps->state = RECV_M6; return msg; @@ -396,11 +397,11 @@ static struct wpabuf * wps_build_m7(struct wps_data *wps) wps_build_encr_settings(wps, msg, plain) || wps_build_wfa_ext(msg, 0, NULL, 0) || wps_build_authenticator(wps, msg)) { - wpabuf_free(plain); + wpabuf_clear_free(plain); wpabuf_free(msg); return NULL; } - wpabuf_free(plain); + wpabuf_clear_free(plain); if (wps->wps->ap && wps->wps->registrar) { /* @@ -1009,11 +1010,11 @@ static enum wps_process_res wps_process_m2(struct wps_data *wps, eattr.key_wrap_auth) || wps_process_creds(wps, eattr.cred, eattr.cred_len, eattr.num_cred, attr->version2 != NULL)) { - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = WPS_MSG_DONE; return WPS_CONTINUE; @@ -1114,7 +1115,7 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps, } if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) { - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } @@ -1124,11 +1125,11 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps, 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); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = SEND_M5; return WPS_CONTINUE; @@ -1167,7 +1168,7 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps, } if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) { - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } @@ -1177,11 +1178,11 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps, 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); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); if (wps->wps->ap) wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS, @@ -1238,7 +1239,7 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps, if (wps_validate_m8_encr(decrypted, wps->wps->ap, attr->version2 != NULL) < 0) { - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } @@ -1251,11 +1252,11 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps, eattr.num_cred, attr->version2 != NULL) || wps_process_ap_settings_e(wps, &eattr, decrypted, attr->version2 != NULL)) { - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = WPS_MSG_DONE; return WPS_CONTINUE; diff --git a/freebsd/contrib/wpa/src/wps/wps_i.h b/freebsd/contrib/wpa/src/wps/wps_i.h index f7154f87..fe0c60bd 100644 --- a/freebsd/contrib/wpa/src/wps/wps_i.h +++ b/freebsd/contrib/wpa/src/wps/wps_i.h @@ -132,8 +132,8 @@ struct wps_data { 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); +int 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, diff --git a/freebsd/contrib/wpa/src/wps/wps_registrar.c b/freebsd/contrib/wpa/src/wps/wps_registrar.c index 261b4557..803569ea 100644 --- a/freebsd/contrib/wpa/src/wps/wps_registrar.c +++ b/freebsd/contrib/wpa/src/wps/wps_registrar.c @@ -2,7 +2,7 @@ /* * Wi-Fi Protected Setup - Registrar - * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -705,7 +705,7 @@ void wps_registrar_deinit(struct wps_registrar *reg) eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); wps_registrar_flush(reg); - wpabuf_free(reg->extra_cred); + wpabuf_clear_free(reg->extra_cred); os_free(reg); } @@ -1579,13 +1579,13 @@ int wps_build_credential_wrap(struct wpabuf *msg, if (wbuf == NULL) return -1; if (wps_build_credential(wbuf, cred)) { - wpabuf_free(wbuf); + wpabuf_clear_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); + wpabuf_clear_free(wbuf); return 0; } @@ -1608,6 +1608,9 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) wps->cred.ssid_len = wps->wps->ssid_len; /* Select the best authentication and encryption type */ + wpa_printf(MSG_DEBUG, + "WPS: Own auth types 0x%x - masked Enrollee auth types 0x%x", + wps->wps->auth_types, wps->auth_type); if (wps->auth_type & WPS_AUTH_WPA2PSK) wps->auth_type = WPS_AUTH_WPA2PSK; else if (wps->auth_type & WPS_AUTH_WPAPSK) @@ -1621,6 +1624,14 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) } wps->cred.auth_type = wps->auth_type; + wpa_printf(MSG_DEBUG, + "WPS: Own encr types 0x%x (rsn: 0x%x, wpa: 0x%x) - masked Enrollee encr types 0x%x", + wps->wps->encr_types, wps->wps->encr_types_rsn, + wps->wps->encr_types_wpa, wps->encr_type); + if (wps->wps->ap && wps->auth_type == WPS_AUTH_WPA2PSK) + wps->encr_type &= wps->wps->encr_types_rsn; + else if (wps->wps->ap && wps->auth_type == WPS_AUTH_WPAPSK) + wps->encr_type &= wps->wps->encr_types_wpa; if (wps->auth_type == WPS_AUTH_WPA2PSK || wps->auth_type == WPS_AUTH_WPAPSK) { if (wps->encr_type & WPS_ENCR_AES) @@ -1742,14 +1753,14 @@ use_provided: return -1; if (wps_build_credential(cred, &wps->cred)) { - wpabuf_free(cred); + wpabuf_clear_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); + wpabuf_clear_free(cred); skip_cred_build: if (wps->wps->registrar->extra_cred) { @@ -1787,7 +1798,7 @@ static struct wpabuf * wps_build_ap_cred(struct wps_data *wps) } if (wps_build_ap_settings(wps, plain)) { - wpabuf_free(plain); + wpabuf_clear_free(plain); wpabuf_free(msg); return NULL; } @@ -1795,7 +1806,7 @@ static struct wpabuf * wps_build_ap_cred(struct wps_data *wps) wpabuf_put_be16(msg, ATTR_CRED); wpabuf_put_be16(msg, wpabuf_len(plain)); wpabuf_put_buf(msg, plain); - wpabuf_free(plain); + wpabuf_clear_free(plain); return msg; } @@ -1855,10 +1866,10 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps) wps_build_key_wrap_auth(wps, plain) || wps_build_encr_settings(wps, msg, plain)) { wpabuf_free(msg); - wpabuf_free(plain); + wpabuf_clear_free(plain); return NULL; } - wpabuf_free(plain); + wpabuf_clear_free(plain); config_in_m2 = 1; } #endif /* CONFIG_WPS_NFC */ @@ -1919,7 +1930,8 @@ static struct wpabuf * wps_build_m4(struct wps_data *wps) wpa_printf(MSG_DEBUG, "WPS: Building Message M4"); - wps_derive_psk(wps, wps->dev_password, wps->dev_password_len); + if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0) + return NULL; plain = wpabuf_alloc(200); if (plain == NULL) @@ -1940,11 +1952,11 @@ static struct wpabuf * wps_build_m4(struct wps_data *wps) wps_build_encr_settings(wps, msg, plain) || wps_build_wfa_ext(msg, 0, NULL, 0) || wps_build_authenticator(wps, msg)) { - wpabuf_free(plain); + wpabuf_clear_free(plain); wpabuf_free(msg); return NULL; } - wpabuf_free(plain); + wpabuf_clear_free(plain); wps->state = RECV_M5; return msg; @@ -1975,11 +1987,11 @@ static struct wpabuf * wps_build_m6(struct wps_data *wps) wps_build_encr_settings(wps, msg, plain) || wps_build_wfa_ext(msg, 0, NULL, 0) || wps_build_authenticator(wps, msg)) { - wpabuf_free(plain); + wpabuf_clear_free(plain); wpabuf_free(msg); return NULL; } - wpabuf_free(plain); + wpabuf_clear_free(plain); wps->wps_pin_revealed = 1; wps->state = RECV_M7; @@ -2012,11 +2024,11 @@ static struct wpabuf * wps_build_m8(struct wps_data *wps) 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); + wpabuf_clear_free(plain); + wpabuf_clear_free(msg); return NULL; } - wpabuf_free(plain); + wpabuf_clear_free(plain); wps->state = RECV_DONE; return msg; @@ -2345,6 +2357,23 @@ static int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth) wpa_printf(MSG_DEBUG, "WPS: Enrollee Authentication Type flags 0x%x", auth_types); +#ifdef WPS_WORKAROUNDS + /* + * Some deployed implementations seem to advertise incorrect information + * in this attribute. A value of 0x1b (WPA2 + WPA + WPAPSK + OPEN, but + * no WPA2PSK) has been reported to be used. Add WPA2PSK to the list to + * avoid issues with building Credentials that do not use the strongest + * actually supported authentication option (that device does support + * WPA2PSK even when it does not claim it here). + */ + if ((auth_types & + (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) == + (WPS_AUTH_WPA2 | WPS_AUTH_WPAPSK)) { + wpa_printf(MSG_DEBUG, + "WPS: Workaround - assume Enrollee supports WPA2PSK based on claimed WPA2 support"); + auth_types |= WPS_AUTH_WPA2PSK; + } +#endif /* WPS_WORKAROUNDS */ wps->auth_type = wps->wps->auth_types & auth_types; if (wps->auth_type == 0) { wpa_printf(MSG_DEBUG, "WPS: No match in supported " @@ -2759,7 +2788,7 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps, } if (wps_validate_m5_encr(decrypted, attr->version2 != NULL) < 0) { - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } @@ -2769,11 +2798,11 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps, 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); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = SEND_M6; return WPS_CONTINUE; @@ -2911,7 +2940,7 @@ static enum wps_process_res wps_process_m7(struct wps_data *wps, if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er, attr->version2 != NULL) < 0) { - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } @@ -2922,12 +2951,12 @@ static enum wps_process_res wps_process_m7(struct wps_data *wps, 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); + wpabuf_clear_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } - wpabuf_free(decrypted); + wpabuf_clear_free(decrypted); wps->state = SEND_M8; return WPS_CONTINUE; diff --git a/freebsd/contrib/wpa/src/wps/wps_upnp.c b/freebsd/contrib/wpa/src/wps/wps_upnp.c index d66ca357..b69d2026 100644 --- a/freebsd/contrib/wpa/src/wps/wps_upnp.c +++ b/freebsd/contrib/wpa/src/wps/wps_upnp.c @@ -1084,6 +1084,7 @@ upnp_wps_get_iface(struct upnp_wps_device_sm *sm, void *priv) void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv) { struct upnp_wps_device_interface *iface; + struct upnp_wps_peer *peer; if (!sm) return; @@ -1104,8 +1105,13 @@ void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv) iface->wps->registrar); dl_list_del(&iface->list); - if (iface->peer.wps) - wps_deinit(iface->peer.wps); + while ((peer = dl_list_first(&iface->peers, struct upnp_wps_peer, + list))) { + if (peer->wps) + wps_deinit(peer->wps); + dl_list_del(&peer->list); + os_free(peer); + } os_free(iface->ctx->ap_pin); os_free(iface->ctx); os_free(iface); @@ -1143,6 +1149,7 @@ upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps, } wpa_printf(MSG_DEBUG, "WPS UPnP: Init interface instance %p", iface); + dl_list_init(&iface->peers); iface->ctx = ctx; iface->wps = wps; iface->priv = priv; diff --git a/freebsd/contrib/wpa/src/wps/wps_upnp.h b/freebsd/contrib/wpa/src/wps/wps_upnp.h index 87b7ab14..b6f6df5e 100644 --- a/freebsd/contrib/wpa/src/wps/wps_upnp.h +++ b/freebsd/contrib/wpa/src/wps/wps_upnp.h @@ -11,11 +11,14 @@ #ifndef WPS_UPNP_H #define WPS_UPNP_H +#include "utils/list.h" + struct upnp_wps_device_sm; struct wps_context; struct wps_data; struct upnp_wps_peer { + struct dl_list list; struct wps_data *wps; }; diff --git a/freebsd/contrib/wpa/src/wps/wps_upnp_i.h b/freebsd/contrib/wpa/src/wps/wps_upnp_i.h index f289fe68..6a7c6272 100644 --- a/freebsd/contrib/wpa/src/wps/wps_upnp_i.h +++ b/freebsd/contrib/wpa/src/wps/wps_upnp_i.h @@ -109,8 +109,7 @@ struct upnp_wps_device_interface { struct wps_context *wps; void *priv; - /* FIX: maintain separate structures for each UPnP peer */ - struct upnp_wps_peer peer; + struct dl_list peers; /* active UPnP peer sessions */ }; /* diff --git a/freebsd/contrib/wpa/src/wps/wps_upnp_ssdp.c b/freebsd/contrib/wpa/src/wps/wps_upnp_ssdp.c index ed972494..4d1c8ed4 100644 --- a/freebsd/contrib/wpa/src/wps/wps_upnp_ssdp.c +++ b/freebsd/contrib/wpa/src/wps/wps_upnp_ssdp.c @@ -102,12 +102,6 @@ static int line_length(const char *l) } -static int str_starts(const char *str, const char *start) -{ - return os_strncmp(str, start, os_strlen(start)) == 0; -} - - /*************************************************************************** * Advertisements. * These are multicast to the world to tell them we are here. diff --git a/freebsd/contrib/wpa/src/wps/wps_upnp_web.c b/freebsd/contrib/wpa/src/wps/wps_upnp_web.c index 8c3bbd1b..09f36d37 100644 --- a/freebsd/contrib/wpa/src/wps/wps_upnp_web.c +++ b/freebsd/contrib/wpa/src/wps/wps_upnp_web.c @@ -302,7 +302,8 @@ static void http_put_empty(struct wpabuf *buf, enum http_reply_code code) * would appear to be required (given that we will be closing it!). */ static void web_connection_parse_get(struct upnp_wps_device_sm *sm, - struct http_request *hreq, char *filename) + struct http_request *hreq, + const char *filename) { struct wpabuf *buf; /* output buffer, allocated */ char *put_length_here; @@ -411,6 +412,15 @@ send_buf: } +static void wps_upnp_peer_del(struct upnp_wps_peer *peer) +{ + dl_list_del(&peer->list); + if (peer->wps) + wps_deinit(peer->wps); + os_free(peer); +} + + static enum http_reply_code web_process_get_device_info(struct upnp_wps_device_sm *sm, struct wpabuf **reply, const char **replyname) @@ -428,7 +438,9 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm, if (!iface || iface->ctx->ap_pin == NULL) return HTTP_INTERNAL_SERVER_ERROR; - peer = &iface->peer; + peer = os_zalloc(sizeof(*peer)); + if (!peer) + return HTTP_INTERNAL_SERVER_ERROR; /* * Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS @@ -438,9 +450,6 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm, * registration. */ - if (peer->wps) - wps_deinit(peer->wps); - os_memset(&cfg, 0, sizeof(cfg)); cfg.wps = iface->wps; cfg.pin = (u8 *) iface->ctx->ap_pin; @@ -457,8 +466,22 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm, *reply = NULL; if (*reply == NULL) { wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo"); + os_free(peer); return HTTP_INTERNAL_SERVER_ERROR; } + + if (dl_list_len(&iface->peers) > 3) { + struct upnp_wps_peer *old; + + old = dl_list_first(&iface->peers, struct upnp_wps_peer, list); + if (old) { + wpa_printf(MSG_DEBUG, "WPS UPnP: Drop oldest active session"); + wps_upnp_peer_del(old); + } + } + dl_list_add_tail(&iface->peers, &peer->list); + /* TODO: Could schedule a timeout to free the entry */ + *replyname = name; return HTTP_OK; } @@ -474,6 +497,8 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data, enum wps_process_res res; enum wsc_op_code op_code; struct upnp_wps_device_interface *iface; + struct wps_parse_attr attr; + struct upnp_wps_peer *tmp, *peer; iface = dl_list_first(&sm->interfaces, struct upnp_wps_device_interface, list); @@ -489,11 +514,56 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data, msg = xml_get_base64_item(data, "NewInMessage", &ret); if (msg == NULL) return ret; - res = wps_process_msg(iface->peer.wps, WSC_UPnP, msg); - if (res == WPS_FAILURE) + + if (wps_parse_msg(msg, &attr)) { + wpa_printf(MSG_DEBUG, + "WPS UPnP: Could not parse PutMessage - NewInMessage"); + wpabuf_free(msg); + return HTTP_BAD_REQUEST; + } + + /* Find a matching active peer session */ + peer = NULL; + dl_list_for_each(tmp, &iface->peers, struct upnp_wps_peer, list) { + if (!tmp->wps) + continue; + if (attr.enrollee_nonce && + os_memcmp(tmp->wps->nonce_e, attr.enrollee_nonce, + WPS_NONCE_LEN) != 0) + continue; /* Enrollee nonce mismatch */ + if (attr.msg_type && + *attr.msg_type != WPS_M2 && + *attr.msg_type != WPS_M2D && + attr.registrar_nonce && + os_memcmp(tmp->wps->nonce_r, attr.registrar_nonce, + WPS_NONCE_LEN) != 0) + continue; /* Registrar nonce mismatch */ + peer = tmp; + break; + } + if (!peer) { + /* + Try to use the first entry in case message could work with + * it. The actual handler function will reject this, if needed. + * This maintains older behavior where only a single peer entry + * was supported. + */ + peer = dl_list_first(&iface->peers, struct upnp_wps_peer, list); + } + if (!peer || !peer->wps) { + wpa_printf(MSG_DEBUG, "WPS UPnP: No active peer entry found"); + wpabuf_free(msg); + return HTTP_BAD_REQUEST; + } + + res = wps_process_msg(peer->wps, WSC_UPnP, msg); + if (res == WPS_FAILURE) { *reply = NULL; - else - *reply = wps_get_msg(iface->peer.wps, &op_code); + wpa_printf(MSG_DEBUG, "WPS UPnP: Drop active peer session"); + wps_upnp_peer_del(peer); + } else { + *reply = wps_get_msg(peer->wps, &op_code); + } wpabuf_free(msg); if (*reply == NULL) return HTTP_INTERNAL_SERVER_ERROR; |