diff options
Diffstat (limited to 'src')
199 files changed, 10662 insertions, 11010 deletions
diff --git a/src/ap/accounting.c b/src/ap/accounting.c index dbfb058..03421b3 100644 --- a/src/ap/accounting.c +++ b/src/ap/accounting.c @@ -236,6 +236,7 @@ static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx) void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) { struct radius_msg *msg; + struct os_time t; int interval; if (sta->acct_session_started) @@ -247,7 +248,8 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) "starting accounting session %08X-%08X", sta->acct_session_id_hi, sta->acct_session_id_lo); - time(&sta->acct_session_start); + os_get_time(&t); + sta->acct_session_start = t.sec; sta->last_rx_bytes = sta->last_tx_bytes = 0; sta->acct_input_gigawords = sta->acct_output_gigawords = 0; hostapd_drv_sta_clear_stats(hapd, sta->addr); diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index e77716b..b24cd90 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -426,6 +426,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf) ssid->dyn_vlan_keys = NULL; } + os_free(conf->time_zone); + #ifdef CONFIG_IEEE80211R { struct ft_remote_r0kh *r0kh, *r0kh_prev; @@ -467,6 +469,12 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->model_url); os_free(conf->upc); #endif /* CONFIG_WPS */ + + os_free(conf->roaming_consortium); + +#ifdef CONFIG_RADIUS_TEST + os_free(conf->dump_msk_file); +#endif /* CONFIG_RADIUS_TEST */ } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 09eed5a..485092d 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -104,7 +104,6 @@ struct hostapd_wpa_psk { u8 addr[ETH_ALEN]; }; -#define EAP_USER_MAX_METHODS 8 struct hostapd_eap_user { struct hostapd_eap_user *next; u8 *identity; @@ -112,7 +111,7 @@ struct hostapd_eap_user { struct { int vendor; u32 method; - } methods[EAP_USER_MAX_METHODS]; + } methods[EAP_MAX_METHODS]; u8 *password; size_t password_len; int phase2; @@ -142,6 +141,13 @@ struct hostapd_wmm_ac_params { }; +#define MAX_ROAMING_CONSORTIUM_LEN 15 + +struct hostapd_roaming_consortium { + u8 len; + u8 oi[MAX_ROAMING_CONSORTIUM_LEN]; +}; + /** * struct hostapd_bss_config - Per-BSS configuration */ @@ -213,6 +219,11 @@ struct hostapd_bss_config { /* dot11AssociationSAQueryRetryTimeout (in TUs) */ int assoc_sa_query_retry_timeout; #endif /* CONFIG_IEEE80211W */ + enum { + PSK_RADIUS_IGNORED = 0, + PSK_RADIUS_ACCEPTED = 1, + PSK_RADIUS_REQUIRED = 2 + } wpa_psk_radius; int wpa_pairwise; int wpa_group; int wpa_group_rekey; @@ -329,11 +340,38 @@ struct hostapd_bss_config { int p2p; int disassoc_low_ack; + int skip_inactivity_poll; #define TDLS_PROHIBIT BIT(0) #define TDLS_PROHIBIT_CHAN_SWITCH BIT(1) int tdls; int disable_11n; + + /* IEEE 802.11v */ + int time_advertisement; + char *time_zone; + + /* IEEE 802.11u - Interworking */ + int interworking; + int access_network_type; + int internet; + int asra; + int esr; + int uesa; + int venue_info_set; + u8 venue_group; + u8 venue_type; + u8 hessid[ETH_ALEN]; + + /* IEEE 802.11u - Roaming Consortium list */ + unsigned int roaming_consortium_count; + struct hostapd_roaming_consortium *roaming_consortium; + + u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */ + +#ifdef CONFIG_RADIUS_TEST + char *dump_msk_file; +#endif /* CONFIG_RADIUS_TEST */ }; @@ -354,12 +392,6 @@ struct hostapd_config { LONG_PREAMBLE = 0, SHORT_PREAMBLE = 1 } preamble; - enum { - CTS_PROTECTION_AUTOMATIC = 0, - CTS_PROTECTION_FORCE_ENABLED = 1, - CTS_PROTECTION_FORCE_DISABLED = 2, - CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3, - } cts_protection_type; int *supported_rates; int *basic_rates; diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 0b6836c..429c187 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -41,117 +41,159 @@ u32 hostapd_sta_flags_to_drv(u32 flags) } -int hostapd_set_ap_wps_ie(struct hostapd_data *hapd) +int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, + struct wpabuf **beacon_ret, + struct wpabuf **proberesp_ret, + struct wpabuf **assocresp_ret) { - struct wpabuf *beacon, *proberesp, *assocresp = NULL; - int ret; + struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL; + u8 buf[200], *pos; - if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL) - return 0; + *beacon_ret = *proberesp_ret = *assocresp_ret = NULL; + + 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); + } + 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); + } + + 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); + } + 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 (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); + } - beacon = hapd->wps_beacon_ie; - proberesp = hapd->wps_probe_resp_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); + } #ifdef CONFIG_P2P - if (hapd->wps_beacon_ie == NULL && hapd->p2p_beacon_ie == NULL) - beacon = NULL; - else { - beacon = wpabuf_alloc((hapd->wps_beacon_ie ? - wpabuf_len(hapd->wps_beacon_ie) : 0) + - (hapd->p2p_beacon_ie ? - wpabuf_len(hapd->p2p_beacon_ie) : 0)); - if (beacon == NULL) - return -1; - if (hapd->wps_beacon_ie) - wpabuf_put_buf(beacon, hapd->wps_beacon_ie); - if (hapd->p2p_beacon_ie) - wpabuf_put_buf(beacon, hapd->p2p_beacon_ie); + 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->wps_probe_resp_ie == NULL && hapd->p2p_probe_resp_ie == NULL) - proberesp = NULL; - else { - proberesp = wpabuf_alloc( - (hapd->wps_probe_resp_ie ? - wpabuf_len(hapd->wps_probe_resp_ie) : 0) + - (hapd->p2p_probe_resp_ie ? - wpabuf_len(hapd->p2p_probe_resp_ie) : 0)); - if (proberesp == NULL) { - wpabuf_free(beacon); - return -1; - } - if (hapd->wps_probe_resp_ie) - wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie); - if (hapd->p2p_probe_resp_ie) - wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_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); } #endif /* CONFIG_P2P */ #ifdef CONFIG_P2P_MANAGER if (hapd->conf->p2p & P2P_MANAGE) { - struct wpabuf *a; - - a = wpabuf_alloc(100 + (beacon ? wpabuf_len(beacon) : 0)); - if (a) { + if (wpabuf_resize(&beacon, 100) == 0) { u8 *start, *p; - if (beacon) - wpabuf_put_buf(a, beacon); - if (beacon != hapd->wps_beacon_ie) - wpabuf_free(beacon); - start = wpabuf_put(a, 0); + start = wpabuf_put(beacon, 0); p = hostapd_eid_p2p_manage(hapd, start); - wpabuf_put(a, p - start); - beacon = a; + wpabuf_put(beacon, p - start); } - a = wpabuf_alloc(100 + (proberesp ? wpabuf_len(proberesp) : - 0)); - if (a) { + if (wpabuf_resize(&proberesp, 100) == 0) { u8 *start, *p; - if (proberesp) - wpabuf_put_buf(a, proberesp); - if (proberesp != hapd->wps_probe_resp_ie) - wpabuf_free(proberesp); - start = wpabuf_put(a, 0); + start = wpabuf_put(proberesp, 0); p = hostapd_eid_p2p_manage(hapd, start); - wpabuf_put(a, p - start); - proberesp = a; + wpabuf_put(proberesp, p - start); } } #endif /* CONFIG_P2P_MANAGER */ #ifdef CONFIG_WPS2 - if (hapd->conf->wps_state) - assocresp = wps_build_assoc_resp_ie(); + 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); + wpabuf_free(a); + } #endif /* CONFIG_WPS2 */ #ifdef CONFIG_P2P_MANAGER if (hapd->conf->p2p & P2P_MANAGE) { - struct wpabuf *a; - a = wpabuf_alloc(100 + (assocresp ? wpabuf_len(assocresp) : - 0)); - if (a) { + if (wpabuf_resize(&assocresp, 100) == 0) { u8 *start, *p; - start = wpabuf_put(a, 0); + start = wpabuf_put(assocresp, 0); p = hostapd_eid_p2p_manage(hapd, start); - wpabuf_put(a, p - start); - if (assocresp) { - wpabuf_put_buf(a, assocresp); - wpabuf_free(assocresp); - } - assocresp = a; + wpabuf_put(assocresp, p - start); } } #endif /* CONFIG_P2P_MANAGER */ + *beacon_ret = beacon; + *proberesp_ret = proberesp; + *assocresp_ret = assocresp; + + return 0; + +fail: + wpabuf_free(beacon); + wpabuf_free(proberesp); + wpabuf_free(assocresp); + return -1; +} + + +void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, + struct wpabuf *beacon, + struct wpabuf *proberesp, + struct wpabuf *assocresp) +{ + wpabuf_free(beacon); + wpabuf_free(proberesp); + wpabuf_free(assocresp); +} + + +int hostapd_set_ap_wps_ie(struct hostapd_data *hapd) +{ + struct wpabuf *beacon, *proberesp, *assocresp; + int ret; + + if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL) + return 0; + + if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) < + 0) + return -1; + ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp, assocresp); - if (beacon != hapd->wps_beacon_ie) - wpabuf_free(beacon); - if (proberesp != hapd->wps_probe_resp_ie) - wpabuf_free(proberesp); - wpabuf_free(assocresp); + hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); return ret; } @@ -211,74 +253,6 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, } -static int hostapd_set_ap_isolate(struct hostapd_data *hapd, int value) -{ - if (hapd->driver == NULL || hapd->driver->set_intra_bss == NULL) - return 0; - return hapd->driver->set_intra_bss(hapd->drv_priv, !value); -} - - -int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection) -{ - int ret = 0; - int preamble; -#ifdef CONFIG_IEEE80211N - u8 buf[60], *ht_capab, *ht_oper, *pos; - - pos = buf; - ht_capab = pos; - pos = hostapd_eid_ht_capabilities(hapd, pos); - ht_oper = pos; - pos = hostapd_eid_ht_operation(hapd, pos); - if (pos > ht_oper && ht_oper > ht_capab && - hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1], - ht_oper + 2, ht_oper[1])) { - wpa_printf(MSG_ERROR, "Could not set HT capabilities " - "for kernel driver"); - ret = -1; - } - -#endif /* CONFIG_IEEE80211N */ - - if (hostapd_set_cts_protect(hapd, use_protection)) { - wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel " - "driver"); - ret = -1; - } - - if (hapd->iface->current_mode && - hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && - hostapd_set_short_slot_time(hapd, - hapd->iface->num_sta_no_short_slot_time - > 0 ? 0 : 1)) { - wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option " - "in kernel driver"); - ret = -1; - } - - if (hapd->iface->num_sta_no_short_preamble == 0 && - hapd->iconf->preamble == SHORT_PREAMBLE) - preamble = SHORT_PREAMBLE; - else - preamble = LONG_PREAMBLE; - if (hostapd_set_preamble(hapd, preamble)) { - wpa_printf(MSG_ERROR, "Could not set preamble for kernel " - "driver"); - ret = -1; - } - - if (hostapd_set_ap_isolate(hapd, hapd->conf->isolate) && - hapd->conf->isolate) { - wpa_printf(MSG_ERROR, "Could not enable AP isolation in " - "kernel driver"); - ret = -1; - } - - return ret; -} - - int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname) { char force_ifname[IFNAMSIZ]; @@ -310,11 +284,41 @@ int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid, } +int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr, + u16 auth_alg) +{ + if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL) + return 0; + return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg); +} + + +int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr, + u16 seq, u16 status, const u8 *ie, size_t len) +{ + if (hapd->driver == NULL || hapd->driver->sta_auth == NULL) + return 0; + return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr, + seq, status, ie, len); +} + + +int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr, + int reassoc, u16 status, const u8 *ie, size_t len) +{ + if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL) + return 0; + return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr, + reassoc, status, ie, len); +} + + int hostapd_sta_add(struct hostapd_data *hapd, const u8 *addr, u16 aid, u16 capability, const u8 *supp_rates, size_t supp_rates_len, u16 listen_interval, - const struct ieee80211_ht_capabilities *ht_capab) + const struct ieee80211_ht_capabilities *ht_capab, + u32 flags, u8 qosinfo) { struct hostapd_sta_add_params params; @@ -331,10 +335,22 @@ int hostapd_sta_add(struct hostapd_data *hapd, params.supp_rates_len = supp_rates_len; params.listen_interval = listen_interval; params.ht_capabilities = ht_capab; + params.flags = hostapd_sta_flags_to_drv(flags); + params.qosinfo = qosinfo; return hapd->driver->sta_add(hapd->drv_priv, ¶ms); } +int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr, + u8 *tspec_ie, size_t tspec_ielen) +{ + if (hapd->driver == NULL || hapd->driver->add_tspec == NULL) + return 0; + return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie, + tspec_ielen); +} + + int hostapd_set_privacy(struct hostapd_data *hapd, int enabled) { if (hapd->driver == NULL || hapd->driver->set_privacy == NULL) @@ -460,16 +476,6 @@ int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, } -int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates, - int *basic_rates, int mode) -{ - if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL) - return 0; - return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates, - basic_rates, mode); -} - - int hostapd_set_country(struct hostapd_data *hapd, const char *country) { if (hapd->driver == NULL || @@ -479,30 +485,6 @@ int hostapd_set_country(struct hostapd_data *hapd, const char *country) } -int hostapd_set_cts_protect(struct hostapd_data *hapd, int value) -{ - if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL) - return 0; - return hapd->driver->set_cts_protect(hapd->drv_priv, value); -} - - -int hostapd_set_preamble(struct hostapd_data *hapd, int value) -{ - if (hapd->driver == NULL || hapd->driver->set_preamble == NULL) - return 0; - return hapd->driver->set_preamble(hapd->drv_priv, value); -} - - -int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value) -{ - if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL) - return 0; - return hapd->driver->set_short_slot_time(hapd->drv_priv, value); -} - - int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, int cw_min, int cw_max, int burst_time) { @@ -513,15 +495,6 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, } -int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr, - const u8 *mask) -{ - if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL) - return 1; - return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask); -} - - struct hostapd_hw_modes * hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, u16 *flags) @@ -542,19 +515,6 @@ int hostapd_driver_commit(struct hostapd_data *hapd) } -int hostapd_set_ht_params(struct hostapd_data *hapd, - const u8 *ht_capab, size_t ht_capab_len, - const u8 *ht_oper, size_t ht_oper_len) -{ - if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL || - ht_capab == NULL || ht_oper == NULL) - return 0; - return hapd->driver->set_ht_params(hapd->drv_priv, - ht_capab, ht_capab_len, - ht_oper, ht_oper_len); -} - - int hostapd_drv_none(struct hostapd_data *hapd) { return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0; @@ -604,11 +564,11 @@ 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) + const void *msg, size_t len, int noack) { if (hapd->driver == NULL || hapd->driver->send_mlme == NULL) return 0; - return hapd->driver->send_mlme(hapd->drv_priv, msg, len); + return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack); } diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index f6076af..835cdde 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -21,13 +21,19 @@ struct wpa_driver_scan_params; struct ieee80211_ht_capabilities; u32 hostapd_sta_flags_to_drv(u32 flags); +int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, + struct wpabuf **beacon, + struct wpabuf **proberesp, + struct wpabuf **assocresp); +void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon, + struct wpabuf *proberesp, + struct wpabuf *assocresp); int hostapd_set_ap_wps_ie(struct hostapd_data *hapd); int hostapd_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized); int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta); int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, int enabled); -int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection); int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname); int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname); int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid, @@ -36,7 +42,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, const u8 *addr, u16 aid, u16 capability, const u8 *supp_rates, size_t supp_rates_len, u16 listen_interval, - const struct ieee80211_ht_capabilities *ht_capab); + const struct ieee80211_ht_capabilities *ht_capab, + u32 flags, u8 qosinfo); 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); @@ -59,23 +66,13 @@ int hostapd_set_rts(struct hostapd_data *hapd, int rts); int hostapd_set_frag(struct hostapd_data *hapd, int frag); int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, int total_flags, int flags_or, int flags_and); -int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates, - int *basic_rates, int mode); int hostapd_set_country(struct hostapd_data *hapd, const char *country); -int hostapd_set_cts_protect(struct hostapd_data *hapd, int value); -int hostapd_set_preamble(struct hostapd_data *hapd, int value); -int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value); int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, int cw_min, int cw_max, int burst_time); -int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr, - const u8 *mask); struct hostapd_hw_modes * hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, u16 *flags); int hostapd_driver_commit(struct hostapd_data *hapd); -int hostapd_set_ht_params(struct hostapd_data *hapd, - const u8 *ht_capab, size_t ht_capab_len, - const u8 *ht_oper, size_t ht_oper_len); int hostapd_drv_none(struct hostapd_data *hapd); int hostapd_driver_scan(struct hostapd_data *hapd, struct wpa_driver_scan_params *params); @@ -90,11 +87,19 @@ int hostapd_drv_set_key(const char *ifname, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len); int hostapd_drv_send_mlme(struct hostapd_data *hapd, - const void *msg, size_t len); + const void *msg, size_t len, int noack); int hostapd_drv_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason); int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, const u8 *addr, int reason); +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, + u16 seq, u16 status, const u8 *ie, size_t len); +int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr, + int reassoc, u16 status, const u8 *ie, size_t len); +int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr, + u8 *tspec_ie, size_t tspec_ielen); #include "drivers/driver.h" @@ -163,16 +168,12 @@ static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd, return hapd->driver->sta_clear_stats(hapd->drv_priv, addr); } -static inline int hostapd_drv_set_beacon(struct hostapd_data *hapd, - const u8 *head, size_t head_len, - const u8 *tail, size_t tail_len, - int dtim_period, int beacon_int) +static inline int hostapd_drv_set_ap(struct hostapd_data *hapd, + struct wpa_driver_ap_params *params) { - if (hapd->driver == NULL || hapd->driver->set_beacon == NULL) + if (hapd->driver == NULL || hapd->driver->set_ap == NULL) return 0; - return hapd->driver->set_beacon(hapd->drv_priv, - head, head_len, tail, tail_len, - dtim_period, beacon_int); + return hapd->driver->set_ap(hapd->drv_priv, params); } static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd, @@ -202,4 +203,13 @@ static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd, return hapd->driver->set_authmode(hapd->drv_priv, auth_algs); } +static inline void hostapd_drv_poll_client(struct hostapd_data *hapd, + const u8 *own_addr, const u8 *addr, + int qos) +{ + if (hapd->driver == NULL || hapd->driver->poll_client == NULL) + return; + hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos); +} + #endif /* AP_DRV_OPS */ diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c index 7c87fde..6f56c95 100644 --- a/src/ap/authsrv.c +++ b/src/ap/authsrv.c @@ -60,7 +60,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, struct eap_user *user) { const struct hostapd_eap_user *eap_user; - int i, count; + int i; eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2); if (eap_user == NULL) @@ -70,10 +70,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, return 0; os_memset(user, 0, sizeof(*user)); - count = EAP_USER_MAX_METHODS; - if (count > EAP_MAX_METHODS) - count = EAP_MAX_METHODS; - for (i = 0; i < count; i++) { + for (i = 0; i < EAP_MAX_METHODS; i++) { user->methods[i].vendor = eap_user->methods[i].vendor; user->methods[i].method = eap_user->methods[i].method; } @@ -120,6 +117,9 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd) srv.eap_req_id_text = conf->eap_req_id_text; srv.eap_req_id_text_len = conf->eap_req_id_text_len; srv.pwd_group = conf->pwd_group; +#ifdef CONFIG_RADIUS_TEST + srv.dump_msk_file = conf->dump_msk_file; +#endif /* CONFIG_RADIUS_TEST */ hapd->radius_srv = radius_server_init(&srv); if (hapd->radius_srv == NULL) { diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 0091064..4d8b277 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -35,6 +35,8 @@ #include "beacon.h" +#ifdef NEED_AP_MLME + static u8 ieee802_11_erp_info(struct hostapd_data *hapd) { u8 erp = 0; @@ -43,23 +45,11 @@ static u8 ieee802_11_erp_info(struct hostapd_data *hapd) hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) return 0; - switch (hapd->iconf->cts_protection_type) { - case CTS_PROTECTION_FORCE_ENABLED: - erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION; - break; - case CTS_PROTECTION_FORCE_DISABLED: - erp = 0; - break; - case CTS_PROTECTION_AUTOMATIC: - if (hapd->iface->olbc) - erp |= ERP_INFO_USE_PROTECTION; - /* continue */ - case CTS_PROTECTION_AUTOMATIC_NO_OLBC: - if (hapd->iface->num_sta_non_erp > 0) { - erp |= ERP_INFO_NON_ERP_PRESENT | - ERP_INFO_USE_PROTECTION; - } - break; + if (hapd->iface->olbc) + erp |= ERP_INFO_USE_PROTECTION; + if (hapd->iface->num_sta_non_erp > 0) { + erp |= ERP_INFO_NON_ERP_PRESENT | + ERP_INFO_USE_PROTECTION; } if (hapd->iface->num_sta_no_short_preamble > 0 || hapd->iconf->preamble == LONG_PREAMBLE) @@ -182,8 +172,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, } -static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len, - struct sta_info *sta) +static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len) { const u8 *ie; size_t ielen; @@ -197,30 +186,134 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len, } +static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, + struct sta_info *sta, + const struct ieee80211_mgmt *req, + int is_p2p, size_t *resp_len) +{ + struct ieee80211_mgmt *resp; + u8 *pos, *epos; + size_t buflen; + +#define MAX_PROBERESP_LEN 768 + buflen = MAX_PROBERESP_LEN; +#ifdef CONFIG_WPS + if (hapd->wps_probe_resp_ie) + buflen += wpabuf_len(hapd->wps_probe_resp_ie); +#endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + if (hapd->p2p_probe_resp_ie) + buflen += wpabuf_len(hapd->p2p_probe_resp_ie); +#endif /* CONFIG_P2P */ + resp = os_zalloc(buflen); + if (resp == NULL) + return NULL; + + epos = ((u8 *) resp) + MAX_PROBERESP_LEN; + + resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_PROBE_RESP); + if (req) + os_memcpy(resp->da, req->sa, ETH_ALEN); + os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); + + os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); + resp->u.probe_resp.beacon_int = + host_to_le16(hapd->iconf->beacon_int); + + /* hardware or low-level driver will setup seq_ctrl and timestamp */ + resp->u.probe_resp.capab_info = + host_to_le16(hostapd_own_capab_info(hapd, sta, 1)); + + pos = resp->u.probe_resp.variable; + *pos++ = WLAN_EID_SSID; + *pos++ = hapd->conf->ssid.ssid_len; + os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len); + pos += hapd->conf->ssid.ssid_len; + + /* Supported rates */ + pos = hostapd_eid_supp_rates(hapd, pos); + + /* DS Params */ + pos = hostapd_eid_ds_params(hapd, pos); + + pos = hostapd_eid_country(hapd, pos, epos - pos); + + /* ERP Information element */ + pos = hostapd_eid_erp_info(hapd, pos); + + /* Extended supported rates */ + pos = hostapd_eid_ext_supp_rates(hapd, pos); + + /* RSN, MDIE, WPA */ + pos = hostapd_eid_wpa(hapd, pos, epos - pos); + +#ifdef CONFIG_IEEE80211N + pos = hostapd_eid_ht_capabilities(hapd, pos); + pos = hostapd_eid_ht_operation(hapd, pos); +#endif /* CONFIG_IEEE80211N */ + + pos = hostapd_eid_ext_capab(hapd, pos); + + pos = hostapd_eid_time_adv(hapd, pos); + pos = hostapd_eid_time_zone(hapd, pos); + + pos = hostapd_eid_interworking(hapd, pos); + pos = hostapd_eid_adv_proto(hapd, pos); + pos = hostapd_eid_roaming_consortium(hapd, pos); + + /* Wi-Fi Alliance WMM */ + pos = hostapd_eid_wmm(hapd, pos); + +#ifdef CONFIG_WPS + if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { + os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), + wpabuf_len(hapd->wps_probe_resp_ie)); + pos += wpabuf_len(hapd->wps_probe_resp_ie); + } +#endif /* CONFIG_WPS */ + +#ifdef CONFIG_P2P + if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p && + hapd->p2p_probe_resp_ie) { + os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), + wpabuf_len(hapd->p2p_probe_resp_ie)); + pos += wpabuf_len(hapd->p2p_probe_resp_ie); + } +#endif /* CONFIG_P2P */ +#ifdef CONFIG_P2P_MANAGER + if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == + P2P_MANAGE) + pos = hostapd_eid_p2p_manage(hapd, pos); +#endif /* CONFIG_P2P_MANAGER */ + + *resp_len = pos - (u8 *) resp; + return (u8 *) resp; +} + + void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { - struct ieee80211_mgmt *resp; + u8 *resp; struct ieee802_11_elems elems; - char *ssid; - u8 *pos, *epos; const u8 *ie; - size_t ssid_len, ie_len; + size_t ie_len; struct sta_info *sta = NULL; - size_t buflen; - size_t i; + size_t i, resp_len; + int noack; ie = mgmt->u.probe_req.variable; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) return; ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); -#ifndef ANDROID_BRCM_P2P_PATCH for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, - mgmt->sa, ie, ie_len) > 0) + mgmt->sa, mgmt->da, mgmt->bssid, + ie, ie_len) > 0) return; -#endif + if (!hapd->iconf->send_probe_response) return; @@ -230,9 +323,6 @@ void handle_probe_req(struct hostapd_data *hapd, return; } - ssid = NULL; - ssid_len = 0; - if ((!elems.ssid || !elems.supp_rates)) { wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " "without SSID or supported rates element", @@ -277,13 +367,9 @@ void handle_probe_req(struct hostapd_data *hapd, (elems.ssid_len == hapd->conf->ssid.ssid_len && os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) == 0)) { - ssid = hapd->conf->ssid.ssid; - ssid_len = hapd->conf->ssid.ssid_len; if (sta) sta->ssid_probe = &hapd->conf->ssid; - } - - if (!ssid) { + } else { if (!(mgmt->da[0] & 0x01)) { char ssid_txt[33]; ieee802_11_print_ssid(ssid_txt, elems.ssid, @@ -296,113 +382,116 @@ void handle_probe_req(struct hostapd_data *hapd, return; } +#ifdef CONFIG_INTERWORKING + if (elems.interworking && elems.interworking_len >= 1) { + u8 ant = elems.interworking[0] & 0x0f; + if (ant != INTERWORKING_ANT_WILDCARD && + ant != hapd->conf->access_network_type) { + wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR + " for mismatching ANT %u ignored", + MAC2STR(mgmt->sa), ant); + return; + } + } + + if (elems.interworking && + (elems.interworking_len == 7 || elems.interworking_len == 9)) { + const u8 *hessid; + if (elems.interworking_len == 7) + hessid = elems.interworking + 1; + else + hessid = elems.interworking + 1 + 2; + if (!is_broadcast_ether_addr(hessid) && + os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) { + wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR + " for mismatching HESSID " MACSTR + " ignored", + MAC2STR(mgmt->sa), MAC2STR(hessid)); + return; + } + } +#endif /* CONFIG_INTERWORKING */ + /* TODO: verify that supp_rates contains at least one matching rate * with AP configuration */ -#define MAX_PROBERESP_LEN 768 - buflen = MAX_PROBERESP_LEN; -#ifdef CONFIG_WPS - if (hapd->wps_probe_resp_ie) - buflen += wpabuf_len(hapd->wps_probe_resp_ie); -#endif /* CONFIG_WPS */ -#ifdef CONFIG_P2P - if (hapd->p2p_probe_resp_ie) - buflen += wpabuf_len(hapd->p2p_probe_resp_ie); -#endif /* CONFIG_P2P */ - resp = os_zalloc(buflen); + + resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL, + &resp_len); if (resp == NULL) return; - epos = ((u8 *) resp) + MAX_PROBERESP_LEN; - resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_PROBE_RESP); - os_memcpy(resp->da, mgmt->sa, ETH_ALEN); - os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); + /* + * If this is a broadcast probe request, apply no ack policy to avoid + * excessive retries. + */ + noack = !!(elems.ssid_len == 0 && is_broadcast_ether_addr(mgmt->da)); - os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); - resp->u.probe_resp.beacon_int = - host_to_le16(hapd->iconf->beacon_int); - - /* hardware or low-level driver will setup seq_ctrl and timestamp */ - resp->u.probe_resp.capab_info = - host_to_le16(hostapd_own_capab_info(hapd, sta, 1)); - - pos = resp->u.probe_resp.variable; - *pos++ = WLAN_EID_SSID; - *pos++ = ssid_len; - os_memcpy(pos, ssid, ssid_len); - pos += ssid_len; - - /* Supported rates */ - pos = hostapd_eid_supp_rates(hapd, pos); - - /* DS Params */ - pos = hostapd_eid_ds_params(hapd, pos); - - pos = hostapd_eid_country(hapd, pos, epos - pos); - - /* ERP Information element */ - pos = hostapd_eid_erp_info(hapd, pos); - - /* Extended supported rates */ - pos = hostapd_eid_ext_supp_rates(hapd, pos); + if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0) + perror("handle_probe_req: send"); - /* RSN, MDIE, WPA */ - pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta); + os_free(resp); -#ifdef CONFIG_IEEE80211N - pos = hostapd_eid_ht_capabilities(hapd, pos); - pos = hostapd_eid_ht_operation(hapd, pos); -#endif /* CONFIG_IEEE80211N */ + wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s " + "SSID", MAC2STR(mgmt->sa), + elems.ssid_len == 0 ? "broadcast" : "our"); +} - pos = hostapd_eid_ext_capab(hapd, pos); - /* Wi-Fi Alliance WMM */ - pos = hostapd_eid_wmm(hapd, pos); +static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, + size_t *resp_len) +{ + /* check probe response offloading caps and print warnings */ + if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD)) + return NULL; #ifdef CONFIG_WPS - if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { - os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), - wpabuf_len(hapd->wps_probe_resp_ie)); - pos += wpabuf_len(hapd->wps_probe_resp_ie); - } + if (hapd->conf->wps_state && hapd->wps_probe_resp_ie && + (!(hapd->iface->probe_resp_offloads & + (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS | + WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2)))) + wpa_printf(MSG_WARNING, "Device is trying to offload WPS " + "Probe Response while not supporting this"); #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P - if ((hapd->conf->p2p & P2P_ENABLED) && elems.p2p && - hapd->p2p_probe_resp_ie) { - os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), - wpabuf_len(hapd->p2p_probe_resp_ie)); - pos += wpabuf_len(hapd->p2p_probe_resp_ie); - } -#endif /* CONFIG_P2P */ -#ifdef CONFIG_P2P_MANAGER - if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == - P2P_MANAGE) - pos = hostapd_eid_p2p_manage(hapd, pos); -#endif /* CONFIG_P2P_MANAGER */ - - if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0) - perror("handle_probe_req: send"); - - os_free(resp); - - wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s " - "SSID", MAC2STR(mgmt->sa), - elems.ssid_len == 0 ? "broadcast" : "our"); + if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie && + !(hapd->iface->probe_resp_offloads & + WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P)) + wpa_printf(MSG_WARNING, "Device is trying to offload P2P " + "Probe Response while not supporting this"); +#endif /* CONFIG_P2P */ + + if (hapd->conf->interworking && + !(hapd->iface->probe_resp_offloads & + WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING)) + wpa_printf(MSG_WARNING, "Device is trying to offload " + "Interworking Probe Response while not supporting " + "this"); + + /* Generate a Probe Response template for the non-P2P case */ + return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len); } +#endif /* NEED_AP_MLME */ + void ieee802_11_set_beacon(struct hostapd_data *hapd) { - struct ieee80211_mgmt *head; - u8 *pos, *tail, *tailpos; + struct ieee80211_mgmt *head = NULL; + u8 *tail = NULL; + size_t head_len = 0, tail_len = 0; + u8 *resp = NULL; + size_t resp_len = 0; + struct wpa_driver_ap_params params; + struct wpabuf *beacon, *proberesp, *assocresp; +#ifdef NEED_AP_MLME u16 capab_info; - size_t head_len, tail_len; + u8 *pos, *tailpos; +#endif /* NEED_AP_MLME */ -#ifdef CONFIG_P2P - if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) == P2P_ENABLED) - goto no_beacon; -#endif /* CONFIG_P2P */ + hapd->beacon_set_done = 1; + +#ifdef NEED_AP_MLME #define BEACON_HEAD_BUF_SIZE 256 #define BEACON_TAIL_BUF_SIZE 512 @@ -474,7 +563,7 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) /* RSN, MDIE, WPA */ tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - - tailpos, NULL); + tailpos); #ifdef CONFIG_IEEE80211N tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); @@ -483,6 +572,16 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) tailpos = hostapd_eid_ext_capab(hapd, tailpos); + /* + * TODO: Time Advertisement element should only be included in some + * DTIM Beacon frames. + */ + tailpos = hostapd_eid_time_adv(hapd, tailpos); + + tailpos = hostapd_eid_interworking(hapd, tailpos); + tailpos = hostapd_eid_adv_proto(hapd, tailpos); + tailpos = hostapd_eid_roaming_consortium(hapd, tailpos); + /* Wi-Fi Alliance WMM */ tailpos = hostapd_eid_wmm(hapd, tailpos); @@ -509,20 +608,75 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) tail_len = tailpos > tail ? tailpos - tail : 0; - if (hostapd_drv_set_beacon(hapd, (u8 *) head, head_len, - tail, tail_len, hapd->conf->dtim_period, - hapd->iconf->beacon_int)) - wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM " - "period"); + resp = hostapd_probe_resp_offloads(hapd, &resp_len); +#endif /* NEED_AP_MLME */ + + os_memset(¶ms, 0, sizeof(params)); + params.head = (u8 *) head; + params.head_len = head_len; + params.tail = tail; + params.tail_len = tail_len; + params.proberesp = resp; + params.proberesp_len = resp_len; + params.dtim_period = hapd->conf->dtim_period; + params.beacon_int = hapd->iconf->beacon_int; + params.basic_rates = hapd->iconf->basic_rates; + params.ssid = (u8 *) hapd->conf->ssid.ssid; + params.ssid_len = hapd->conf->ssid.ssid_len; + params.pairwise_ciphers = hapd->conf->rsn_pairwise ? + hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise; + params.group_cipher = hapd->conf->wpa_group; + params.key_mgmt_suites = hapd->conf->wpa_key_mgmt; + params.auth_algs = hapd->conf->auth_algs; + params.wpa_version = hapd->conf->wpa; + params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa || + (hapd->conf->ieee802_1x && + (hapd->conf->default_wep_key_len || + hapd->conf->individual_wep_key_len)); + switch (hapd->conf->ignore_broadcast_ssid) { + case 0: + params.hide_ssid = NO_SSID_HIDING; + break; + case 1: + params.hide_ssid = HIDDEN_SSID_ZERO_LEN; + break; + case 2: + params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS; + break; + } + hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp); + params.beacon_ies = beacon; + params.proberesp_ies = proberesp; + params.assocresp_ies = assocresp; + params.isolate = hapd->conf->isolate; +#ifdef NEED_AP_MLME + params.cts_protect = !!(ieee802_11_erp_info(hapd) & + ERP_INFO_USE_PROTECTION); + params.preamble = hapd->iface->num_sta_no_short_preamble == 0 && + hapd->iconf->preamble == SHORT_PREAMBLE; + if (hapd->iface->current_mode && + hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) + params.short_slot_time = + hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1; + else + params.short_slot_time = -1; + if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n) + params.ht_opmode = -1; + else + params.ht_opmode = hapd->iface->ht_op_mode; +#endif /* NEED_AP_MLME */ + params.interworking = hapd->conf->interworking; + if (hapd->conf->interworking && + !is_zero_ether_addr(hapd->conf->hessid)) + params.hessid = hapd->conf->hessid; + params.access_network_type = hapd->conf->access_network_type; + if (hostapd_drv_set_ap(hapd, ¶ms)) + wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); + hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); os_free(tail); os_free(head); - -#ifdef CONFIG_P2P -no_beacon: -#endif /* CONFIG_P2P */ - hostapd_set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) & - ERP_INFO_USE_PROTECTION)); + os_free(resp); } diff --git a/src/ap/beacon.h b/src/ap/beacon.h index c1510e1..a944f5f 100644 --- a/src/ap/beacon.h +++ b/src/ap/beacon.h @@ -20,17 +20,7 @@ struct ieee80211_mgmt; void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len); -#ifdef NEED_AP_MLME void ieee802_11_set_beacon(struct hostapd_data *hapd); void ieee802_11_set_beacons(struct hostapd_iface *iface); -#else /* NEED_AP_MLME */ -static inline void ieee802_11_set_beacon(struct hostapd_data *hapd) -{ -} - -static inline void ieee802_11_set_beacons(struct hostapd_iface *iface) -{ -} -#endif /* NEED_AP_MLME */ #endif /* BEACON_H */ diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 10e3af9..b7febdc 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -19,7 +19,6 @@ #include "drivers/driver.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" -#include "common/wpa_ctrl.h" #include "crypto/random.h" #include "p2p/p2p.h" #include "wps/wps.h" @@ -28,25 +27,22 @@ #include "sta_info.h" #include "accounting.h" #include "tkip_countermeasures.h" -#include "iapp.h" #include "ieee802_1x.h" #include "wpa_auth.h" -#include "wmm.h" #include "wps_hostapd.h" #include "ap_drv_ops.h" #include "ap_config.h" int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, - const u8 *ie, size_t ielen, int reassoc) + const u8 *req_ies, size_t req_ies_len, int reassoc) { struct sta_info *sta; int new_assoc, res; struct ieee802_11_elems elems; -#ifdef CONFIG_P2P - const u8 *all_ies = ie; - size_t all_ies_len = ielen; -#endif /* CONFIG_P2P */ + const u8 *ie; + size_t ielen; + u16 reason = WLAN_REASON_UNSPECIFIED; if (addr == NULL) { /* @@ -65,7 +61,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); - ieee802_11_parse_elems(ie, ielen, &elems, 0); + ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); if (elems.wps_ie) { ie = elems.wps_ie - 2; ielen = elems.wps_ie_len + 2; @@ -93,18 +89,19 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, if (sta == NULL) return -1; } - sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); #ifdef CONFIG_P2P if (elems.p2p) { wpabuf_free(sta->p2p_ie); - sta->p2p_ie = ieee802_11_vendor_ie_concat(all_ies, all_ies_len, + sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, P2P_IE_VENDOR_TYPE); } #endif /* CONFIG_P2P */ if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { +#ifdef CONFIG_WPS if (hapd->conf->wps_state) { wpa_printf(MSG_DEBUG, "STA did not include " "WPA/RSN IE in (Re)Association " @@ -112,15 +109,29 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, sta->flags |= WLAN_STA_MAYBE_WPS; goto skip_wpa_check; } +#endif /* CONFIG_WPS */ wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); return -1; } +#ifdef CONFIG_WPS if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { + struct wpabuf *wps; sta->flags |= WLAN_STA_WPS; + wps = ieee802_11_vendor_ie_concat(ie, ielen, + WPS_IE_VENDOR_TYPE); + if (wps) { + if (wps_is_20(wps)) { + wpa_printf(MSG_DEBUG, "WPS: STA " + "supports WPS 2.0"); + sta->flags |= WLAN_STA_WPS2; + } + wpabuf_free(wps); + } goto skip_wpa_check; } +#endif /* CONFIG_WPS */ if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, @@ -133,52 +144,55 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, NULL, 0); if (res != WPA_IE_OK) { - int resp; wpa_printf(MSG_DEBUG, "WPA/RSN information element " "rejected? (res %u)", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); if (res == WPA_INVALID_GROUP) - resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; + reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; else if (res == WPA_INVALID_PAIRWISE) - resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; + reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; else if (res == WPA_INVALID_AKMP) - resp = WLAN_REASON_AKMP_NOT_VALID; + reason = WLAN_REASON_AKMP_NOT_VALID; #ifdef CONFIG_IEEE80211W else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) - resp = WLAN_REASON_INVALID_IE; + reason = WLAN_REASON_INVALID_IE; else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) - resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; + reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; #endif /* CONFIG_IEEE80211W */ else - resp = WLAN_REASON_INVALID_IE; - hostapd_drv_sta_disassoc(hapd, sta->addr, resp); - ap_free_sta(hapd, sta); - return -1; + reason = WLAN_REASON_INVALID_IE; + goto fail; } } else if (hapd->conf->wps_state) { -#ifdef CONFIG_WPS_STRICT - if (ie) { - struct wpabuf *wps; - wps = ieee802_11_vendor_ie_concat(ie, ielen, +#ifdef CONFIG_WPS + struct wpabuf *wps; + if (req_ies) + wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, WPS_IE_VENDOR_TYPE); - if (wps && wps_validate_assoc_req(wps) < 0) { - hostapd_drv_sta_disassoc( - hapd, sta->addr, - WLAN_REASON_INVALID_IE); - ap_free_sta(hapd, sta); - wpabuf_free(wps); - return -1; - } + else + wps = NULL; +#ifdef CONFIG_WPS_STRICT + if (wps && wps_validate_assoc_req(wps) < 0) { + reason = WLAN_REASON_INVALID_IE; wpabuf_free(wps); + goto fail; } #endif /* CONFIG_WPS_STRICT */ - if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && - os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { + if (wps) { sta->flags |= WLAN_STA_WPS; + if (wps_is_20(wps)) { + wpa_printf(MSG_DEBUG, "WPS: STA supports " + "WPS 2.0"); + sta->flags |= WLAN_STA_WPS2; + } } else sta->flags |= WLAN_STA_MAYBE_WPS; + wpabuf_free(wps); +#endif /* CONFIG_WPS */ } +#ifdef CONFIG_WPS skip_wpa_check: +#endif /* CONFIG_WPS */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; @@ -189,11 +203,18 @@ skip_wpa_check: ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); #ifdef CONFIG_P2P - p2p_group_notif_assoc(hapd->p2p_group, sta->addr, - all_ies, all_ies_len); + if (req_ies) { + p2p_group_notif_assoc(hapd->p2p_group, sta->addr, + req_ies, req_ies_len); + } #endif /* CONFIG_P2P */ return 0; + +fail: + hostapd_drv_sta_disassoc(hapd, sta->addr, reason); + ap_free_sta(hapd, sta); + return -1; } @@ -224,14 +245,8 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) return; } + ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#ifdef ANDROID_BRCM_P2P_PATCH - if(hapd->msg_ctx_parent) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#endif /* ANDROID_BRCM_P2P_PATCH */ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); @@ -255,8 +270,8 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr) } -int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, - const u8 *ie, size_t ie_len) +int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, + const u8 *bssid, const u8 *ie, size_t ie_len) { size_t i; int ret = 0; @@ -267,7 +282,7 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, random_add_randomness(sa, ETH_ALEN); for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, - sa, ie, ie_len) > 0) { + sa, da, bssid, ie, ie_len) > 0) { ret = 1; break; } @@ -280,46 +295,6 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, #ifdef NEED_AP_MLME -static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) -{ - u16 fc, type, stype; - - /* - * PS-Poll frames are 16 bytes. All other frames are - * 24 bytes or longer. - */ - if (len < 16) - return NULL; - - fc = le_to_host16(hdr->frame_control); - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - - switch (type) { - case WLAN_FC_TYPE_DATA: - if (len < 24) - return NULL; - switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { - case WLAN_FC_FROMDS | WLAN_FC_TODS: - case WLAN_FC_TODS: - return hdr->addr1; - case WLAN_FC_FROMDS: - return hdr->addr2; - default: - return NULL; - } - case WLAN_FC_TYPE_CTRL: - if (stype != WLAN_FC_STYPE_PSPOLL) - return NULL; - return hdr->addr1; - case WLAN_FC_TYPE_MGMT: - return hdr->addr3; - default: - return NULL; - } -} - - #define HAPD_BROADCAST ((struct hostapd_data *) -1) static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, @@ -343,17 +318,14 @@ static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, - const u8 *frame, size_t len) + const u8 *bssid, const u8 *addr, + int wds) { - const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame; - u16 fc = le_to_host16(hdr->frame_control); - hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); + hapd = get_hapd_bssid(hapd->iface, bssid); if (hapd == NULL || hapd == HAPD_BROADCAST) return; - ieee802_11_rx_from_unknown(hapd, hdr->addr2, - (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == - (WLAN_FC_TODS | WLAN_FC_FROMDS)); + ieee802_11_rx_from_unknown(hapd, addr, wds); } @@ -497,6 +469,23 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { struct hostapd_data *hapd = ctx; +#ifndef CONFIG_NO_STDOUT_DEBUG + int level = MSG_DEBUG; + + if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame && + data->rx_mgmt.frame_len >= 24) { + const struct ieee80211_hdr *hdr; + u16 fc; + hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame; + fc = le_to_host16(hdr->frame_control); + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) + level = MSG_EXCESSIVE; + } + + wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received", + event_to_string(event), event); +#endif /* CONFIG_NO_STDOUT_DEBUG */ switch (event) { case EVENT_MICHAEL_MIC_FAILURE: @@ -532,9 +521,19 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } break; + case EVENT_EAPOL_TX_STATUS: + hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst, + data->eapol_tx_status.data, + data->eapol_tx_status.data_len, + data->eapol_tx_status.ack); + break; + case EVENT_DRIVER_CLIENT_POLL_OK: + hostapd_client_poll_ok(hapd, data->client_poll.addr); + break; case EVENT_RX_FROM_UNKNOWN: - hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame, - data->rx_from_unknown.len); + hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid, + data->rx_from_unknown.addr, + data->rx_from_unknown.wds); break; case EVENT_RX_MGMT: hostapd_mgmt_rx(hapd, &data->rx_mgmt); @@ -545,6 +544,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->rx_probe_req.ie == NULL) break; hostapd_probe_req_rx(hapd, data->rx_probe_req.sa, + data->rx_probe_req.da, + data->rx_probe_req.bssid, data->rx_probe_req.ie, data->rx_probe_req.ie_len); break; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index f00a544..0c5ee2e 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -61,9 +61,11 @@ static void hostapd_reload_bss(struct hostapd_data *hapd) else hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); - if (hapd->conf->wpa && hapd->wpa_auth == NULL) + if (hapd->conf->wpa && hapd->wpa_auth == NULL) { hostapd_setup_wpa(hapd); - else if (hapd->conf->wpa) { + if (hapd->wpa_auth) + wpa_init_keys(hapd->wpa_auth); + } else if (hapd->conf->wpa) { const u8 *wpa_ie; size_t wpa_ie_len; hostapd_reconfig_wpa(hapd); @@ -259,6 +261,8 @@ static void hostapd_cleanup(struct hostapd_data *hapd) wpabuf_free(hapd->p2p_probe_resp_ie); hapd->p2p_probe_resp_ie = NULL; #endif /* CONFIG_P2P */ + + wpabuf_free(hapd->time_adv); } @@ -287,6 +291,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface) iface->hw_features = NULL; os_free(iface->current_rates); iface->current_rates = NULL; + os_free(iface->basic_rates); + iface->basic_rates = NULL; ap_list_deinit(iface); hostapd_config_free(iface->conf); iface->conf = NULL; @@ -341,12 +347,13 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd) if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL) return 0; - wpa_printf(MSG_DEBUG, "Flushing old station entries"); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries"); if (hostapd_flush(hapd)) { - wpa_printf(MSG_WARNING, "Could not connect to kernel driver."); + wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to " + "kernel driver"); ret = -1; } - wpa_printf(MSG_DEBUG, "Deauthenticate all stations"); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations"); os_memset(addr, 0xff, ETH_ALEN); hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); hostapd_free_stas(hapd); @@ -367,7 +374,6 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) u8 mask[ETH_ALEN] = { 0 }; struct hostapd_data *hapd = iface->bss[0]; unsigned int i = iface->conf->num_bss, bits = 0, j; - int res; int auto_addr = 0; if (hostapd_drv_none(hapd)) @@ -431,17 +437,6 @@ skip_mask_ext: wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)", (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits); - res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask); - if (res == 0) - return 0; - - if (res < 0) { - wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask " - MACSTR " for start address " MACSTR ".", - MAC2STR(mask), MAC2STR(hapd->own_addr)); - return -1; - } - if (!auto_addr) return 0; @@ -639,6 +634,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) ieee802_11_set_beacon(hapd); + if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) + return -1; + if (hapd->driver && hapd->driver->set_operstate) hapd->driver->set_operstate(hapd->drv_priv, 1); @@ -746,7 +744,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) } if (iface->current_mode) { - if (hostapd_prepare_rates(hapd, iface->current_mode)) { + if (hostapd_prepare_rates(iface, iface->current_mode)) { wpa_printf(MSG_ERROR, "Failed to prepare rates " "table."); hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 3764be4..c6f6205 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -31,7 +31,8 @@ enum wps_event; union wps_event_data; struct hostapd_probereq_cb { - int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len); + int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid, + const u8 *ie, size_t ie_len); void *ctx; }; @@ -81,10 +82,7 @@ struct hostapd_data { struct sta_info *sta, int reassoc); void *msg_ctx; /* ctx for wpa_msg() calls */ -#ifdef ANDROID_BRCM_P2P_PATCH - /* Sending the event to parent is required as SSL listens on parent ctrl iface */ - void *msg_ctx_parent; /* ctx for wpa_msg() calls */ -#endif /*ANDROID_BRCM_P2P_PATCH*/ + 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; @@ -111,6 +109,10 @@ struct hostapd_data { int parameter_set_count; + /* Time Advertisement */ + u8 time_update_counter; + struct wpabuf *time_adv; + #ifdef CONFIG_FULL_DYNAMIC_VLAN struct full_dynamic_vlan *full_dynamic_vlan; #endif /* CONFIG_FULL_DYNAMIC_VLAN */ @@ -118,6 +120,7 @@ struct hostapd_data { struct l2_packet_data *l2; struct wps_context *wps; + int beacon_set_done; struct wpabuf *wps_beacon_ie; struct wpabuf *wps_probe_resp_ie; #ifdef CONFIG_WPS @@ -146,7 +149,7 @@ struct hostapd_data { void *wps_event_cb_ctx; void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr, - int authorized); + int authorized, const u8 *p2p_dev_addr); void *sta_authorized_cb_ctx; void (*setup_complete_cb)(void *ctx); @@ -189,6 +192,13 @@ struct hostapd_iface { struct ap_info *ap_iter_list; unsigned int drv_flags; + + /* + * A bitmap of supported protocols for probe response offload. See + * struct wpa_driver_capa in driver.h + */ + unsigned int probe_resp_offloads; + struct hostapd_hw_modes *hw_features; int num_hw_features; struct hostapd_hw_modes *current_mode; @@ -196,6 +206,7 @@ struct hostapd_iface { * current_mode->channels */ int num_rates; struct hostapd_rate_data *current_rates; + int *basic_rates; int freq; u16 hw_flags; @@ -251,6 +262,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, /* utils.c */ int hostapd_register_probereq_cb(struct hostapd_data *hapd, int (*cb)(void *ctx, const u8 *sa, + const u8 *da, const u8 *bssid, const u8 *ie, size_t ie_len), void *ctx); void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr); @@ -260,7 +272,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *ie, size_t ielen, int reassoc); void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr); -int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, - const u8 *ie, size_t ie_len); +int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, + const u8 *bssid, const u8 *ie, size_t ie_len); #endif /* HOSTAPD_H */ diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index 86f6811..8c6fef2 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -2,7 +2,7 @@ * hostapd / Hardware feature query and different modes * Copyright 2002-2003, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -101,7 +101,7 @@ int hostapd_get_hw_features(struct hostapd_iface *iface) } -int hostapd_prepare_rates(struct hostapd_data *hapd, +int hostapd_prepare_rates(struct hostapd_iface *iface, struct hostapd_hw_modes *mode) { int i, num_basic_rates = 0; @@ -110,8 +110,8 @@ int hostapd_prepare_rates(struct hostapd_data *hapd, int basic_rates_g[] = { 10, 20, 55, 110, -1 }; int *basic_rates; - if (hapd->iconf->basic_rates) - basic_rates = hapd->iconf->basic_rates; + if (iface->conf->basic_rates) + basic_rates = iface->conf->basic_rates; else switch (mode->mode) { case HOSTAPD_MODE_IEEE80211A: basic_rates = basic_rates_a; @@ -126,18 +126,20 @@ int hostapd_prepare_rates(struct hostapd_data *hapd, return -1; } - if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates, - basic_rates, mode->mode)) { - wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel " - "module"); - } + i = 0; + while (basic_rates[i] >= 0) + i++; + os_free(iface->basic_rates); + iface->basic_rates = os_malloc(i * sizeof(int)); + if (iface->basic_rates) + os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int)); - os_free(hapd->iface->current_rates); - hapd->iface->num_rates = 0; + os_free(iface->current_rates); + iface->num_rates = 0; - hapd->iface->current_rates = + iface->current_rates = os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data)); - if (!hapd->iface->current_rates) { + if (!iface->current_rates) { wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " "table."); return -1; @@ -146,27 +148,27 @@ int hostapd_prepare_rates(struct hostapd_data *hapd, for (i = 0; i < mode->num_rates; i++) { struct hostapd_rate_data *rate; - if (hapd->iconf->supported_rates && - !hostapd_rate_found(hapd->iconf->supported_rates, + if (iface->conf->supported_rates && + !hostapd_rate_found(iface->conf->supported_rates, mode->rates[i])) continue; - rate = &hapd->iface->current_rates[hapd->iface->num_rates]; + rate = &iface->current_rates[iface->num_rates]; rate->rate = mode->rates[i]; if (hostapd_rate_found(basic_rates, rate->rate)) { rate->flags |= HOSTAPD_RATE_BASIC; num_basic_rates++; } wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", - hapd->iface->num_rates, rate->rate, rate->flags); - hapd->iface->num_rates++; + iface->num_rates, rate->rate, rate->flags); + iface->num_rates++; } - if ((hapd->iface->num_rates == 0 || num_basic_rates == 0) && - (!hapd->iconf->ieee80211n || !hapd->iconf->require_ht)) { + if ((iface->num_rates == 0 || num_basic_rates == 0) && + (!iface->conf->ieee80211n || !iface->conf->require_ht)) { wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " "rate sets (%d,%d).", - hapd->iface->num_rates, num_basic_rates); + iface->num_rates, num_basic_rates); return -1; } @@ -407,20 +409,6 @@ static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, } -static void wpa_scan_results_free(struct wpa_scan_results *res) -{ - size_t i; - - if (res == NULL) - return; - - for (i = 0; i < res->num; i++) - os_free(res->res[i]); - os_free(res->res); - os_free(res); -} - - static void ieee80211n_check_scan(struct hostapd_iface *iface) { struct wpa_scan_results *scan_res; @@ -630,7 +618,8 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_WARNING, "Hardware does not support configured mode " - "(%d)", (int) iface->conf->hw_mode); + "(%d) (hw_mode in hostapd.conf)", + (int) iface->conf->hw_mode); return -2; } @@ -642,8 +631,15 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) if (chan->flag & HOSTAPD_CHAN_DISABLED) { wpa_printf(MSG_ERROR, "channel [%i] (%i) is disabled for " - "use in AP mode, flags: 0x%x", - j, chan->chan, chan->flag); + "use in AP mode, flags: 0x%x%s%s%s", + j, chan->chan, chan->flag, + chan->flag & HOSTAPD_CHAN_NO_IBSS ? + " NO-IBSS" : "", + chan->flag & + HOSTAPD_CHAN_PASSIVE_SCAN ? + " PASSIVE-SCAN" : "", + chan->flag & HOSTAPD_CHAN_RADAR ? + " RADAR" : ""); } else { ok = 1; break; diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h index b84bca6..abadcd1 100644 --- a/src/ap/hw_features.h +++ b/src/ap/hw_features.h @@ -2,6 +2,7 @@ * hostapd / Hardware feature query and different modes * Copyright 2002-2003, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -25,7 +26,7 @@ const char * hostapd_hw_mode_txt(int mode); int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan); int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq); int hostapd_check_ht_capab(struct hostapd_iface *iface); -int hostapd_prepare_rates(struct hostapd_data *hapd, +int hostapd_prepare_rates(struct hostapd_iface *iface, struct hostapd_hw_modes *mode); #else /* NEED_AP_MLME */ static inline void @@ -59,7 +60,7 @@ static inline int hostapd_check_ht_capab(struct hostapd_iface *iface) return 0; } -static inline int hostapd_prepare_rates(struct hostapd_data *hapd, +static inline int hostapd_prepare_rates(struct hostapd_iface *iface, struct hostapd_hw_modes *mode) { return 0; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index e0a3a36..a1a7270 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1,6 +1,6 @@ /* * hostapd / IEEE 802.11 Management - * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -163,59 +163,6 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, } -u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) -{ - u8 *pos = eid; - - if ((hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) == - 0) - return eid; - - *pos++ = WLAN_EID_EXT_CAPAB; - *pos++ = 5; - *pos++ = 0x00; - *pos++ = 0x00; - *pos++ = 0x00; - *pos++ = 0x00; - *pos = 0x00; - if (hapd->conf->tdls & TDLS_PROHIBIT) - *pos |= 0x40; /* Bit 38 - TDLS Prohibited */ - if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) - *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */ - pos++; - - return pos; -} - - -#ifdef CONFIG_IEEE80211W -static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, - struct sta_info *sta, u8 *eid) -{ - u8 *pos = eid; - u32 timeout, tu; - struct os_time now, passed; - - *pos++ = WLAN_EID_TIMEOUT_INTERVAL; - *pos++ = 5; - *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; - os_get_time(&now); - os_time_sub(&now, &sta->sa_query_start, &passed); - tu = (passed.sec * 1000000 + passed.usec) / 1024; - if (hapd->conf->assoc_sa_query_max_timeout > tu) - timeout = hapd->conf->assoc_sa_query_max_timeout - tu; - else - timeout = 0; - if (timeout < hapd->conf->assoc_sa_query_max_timeout) - timeout++; /* add some extra time for local timers */ - WPA_PUT_LE32(pos, timeout); - pos += 4; - - return pos; -} -#endif /* CONFIG_IEEE80211W */ - - void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len) { int i; @@ -322,7 +269,7 @@ static void send_auth_reply(struct hostapd_data *hapd, " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)", MAC2STR(dst), auth_alg, auth_transaction, resp, (unsigned long) ies_len); - if (hostapd_drv_send_mlme(hapd, reply, rlen) < 0) + if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0) perror("send_auth_reply: send"); os_free(buf); @@ -366,6 +313,8 @@ static void handle_auth(struct hostapd_data *hapd, const u8 *challenge = NULL; u32 session_timeout, acct_interim_interval; int vlan_id = 0; + u8 psk[PMK_LEN]; + int has_psk = 0; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; size_t resp_ies_len = 0; @@ -400,9 +349,7 @@ static void handle_auth(struct hostapd_data *hapd, if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) && auth_alg == WLAN_AUTH_OPEN) || #ifdef CONFIG_IEEE80211R - (hapd->conf->wpa && - (hapd->conf->wpa_key_mgmt & - (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) && + (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && auth_alg == WLAN_AUTH_FT) || #endif /* CONFIG_IEEE80211R */ ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) && @@ -430,7 +377,9 @@ static void handle_auth(struct hostapd_data *hapd, res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, &session_timeout, - &acct_interim_interval, &vlan_id); + &acct_interim_interval, &vlan_id, + psk, &has_psk); + if (res == HOSTAPD_ACL_REJECT) { printf("Station " MACSTR " not allowed to authenticate.\n", MAC2STR(mgmt->sa)); @@ -468,6 +417,16 @@ static void handle_auth(struct hostapd_data *hapd, HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); } + if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) { + os_free(sta->psk); + sta->psk = os_malloc(PMK_LEN); + if (sta->psk) + os_memcpy(sta->psk, psk, PMK_LEN); + } else { + os_free(sta->psk); + sta->psk = NULL; + } + sta->flags &= ~WLAN_STA_PREAUTH; ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); @@ -592,15 +551,22 @@ static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta, const u8 *wmm_ie, size_t wmm_ie_len) { sta->flags &= ~WLAN_STA_WMM; + sta->qosinfo = 0; if (wmm_ie && hapd->conf->wmm_enabled) { - if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) + struct wmm_information_element *wmm; + + if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "invalid WMM element in association " "request"); - else - sta->flags |= WLAN_STA_WMM; + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + sta->flags |= WLAN_STA_WMM; + wmm = (struct wmm_information_element *) wmm_ie; + sta->qosinfo = wmm->qos_info; } return WLAN_STATUS_SUCCESS; } @@ -701,7 +667,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } #ifdef CONFIG_WPS - sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); if (hapd->conf->wps_state && elems.wps_ie) { wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association " "Request - assume WPS is used"); @@ -709,6 +675,10 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, wpabuf_free(sta->wps_ie); sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_IE_VENDOR_TYPE); + if (sta->wps_ie && wps_is_20(sta->wps_ie)) { + wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0"); + sta->flags |= WLAN_STA_WPS2; + } wpa_ie = NULL; wpa_ie_len = 0; if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) { @@ -854,7 +824,7 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr, send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth); reply.u.deauth.reason_code = host_to_le16(reason_code); - if (hostapd_drv_send_mlme(hapd, &reply, send_len) < 0) + if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0) wpa_printf(MSG_INFO, "Failed to send deauth: %s", strerror(errno)); } @@ -917,7 +887,8 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, p = hostapd_eid_wmm(hapd, p); #ifdef CONFIG_WPS - if (sta->flags & WLAN_STA_WPS) { + if ((sta->flags & WLAN_STA_WPS) || + ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) { struct wpabuf *wps = wps_build_assoc_resp_ie(); if (wps) { os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps)); @@ -959,7 +930,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, send_len += p - reply->u.assoc_resp.variable; - if (hostapd_drv_send_mlme(hapd, reply, send_len) < 0) + if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", strerror(errno)); } @@ -1160,15 +1131,8 @@ static void handle_disassoc(struct hostapd_data *hapd, return; } + ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#ifdef ANDROID_BRCM_P2P_PATCH - if(hapd->msg_ctx_parent) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#endif /* ANDROID_BRCM_P2P_PATCH */ - wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "disassociated"); @@ -1199,32 +1163,26 @@ static void handle_deauth(struct hostapd_data *hapd, struct sta_info *sta; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) { - wpa_msg(hapd, MSG_DEBUG, "handle_deauth - too short payload " - "(len=%lu)", (unsigned long) len); + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short " + "payload (len=%lu)", (unsigned long) len); return; } - wpa_msg(hapd, MSG_DEBUG, "deauthentication: STA=" MACSTR + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR " reason_code=%d", MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { - wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " trying to " - "deauthenticate, but it is not authenticated", + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " + "to deauthenticate, but it is not authenticated", MAC2STR(mgmt->sa)); return; } + ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#ifdef ANDROID_BRCM_P2P_PATCH - if(hapd->msg_ctx_parent) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#endif /* ANDROID_BRCM_P2P_PATCH */ wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "deauthenticated"); @@ -1259,81 +1217,11 @@ static void handle_beacon(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211W -/* MLME-SAQuery.request */ -void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, - const u8 *addr, const u8 *trans_id) -{ - struct ieee80211_mgmt mgmt; - u8 *end; - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to " - MACSTR, MAC2STR(addr)); - wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", - trans_id, WLAN_SA_QUERY_TR_ID_LEN); - - os_memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt.da, addr, ETH_ALEN); - os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); - mgmt.u.action.category = WLAN_ACTION_SA_QUERY; - mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST; - os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; - if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt) < 0) - perror("ieee802_11_send_sa_query_req: send"); -} - - -static void hostapd_sa_query_request(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt) -{ - struct sta_info *sta; - struct ieee80211_mgmt resp; - u8 *end; - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from " - MACSTR, MAC2STR(mgmt->sa)); - wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", - mgmt->u.action.u.sa_query_resp.trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - - sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request " - "from unassociated STA " MACSTR, MAC2STR(mgmt->sa)); - return; - } - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to " - MACSTR, MAC2STR(mgmt->sa)); - - os_memset(&resp, 0, sizeof(resp)); - resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(resp.da, mgmt->sa, ETH_ALEN); - os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN); - os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN); - resp.u.action.category = WLAN_ACTION_SA_QUERY; - resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE; - os_memcpy(resp.u.action.u.sa_query_req.trans_id, - mgmt->u.action.u.sa_query_req.trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; - if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp) < 0) - perror("hostapd_sa_query_request: send"); -} - - static void hostapd_sa_query_action(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { - struct sta_info *sta; const u8 *end; - int i; end = mgmt->u.action.u.sa_query_resp.trans_id + WLAN_SA_QUERY_TR_ID_LEN; @@ -1343,50 +1231,9 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd, return; } - if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) { - hostapd_sa_query_request(hapd, mgmt); - return; - } - - if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query " - "Action %d", mgmt->u.action.u.sa_query_resp.action); - return; - } - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from " - MACSTR, MAC2STR(mgmt->sa)); - wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", - mgmt->u.action.u.sa_query_resp.trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - - /* MLME-SAQuery.confirm */ - - sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL || sta->sa_query_trans_id == NULL) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with " - "pending SA Query request found"); - return; - } - - for (i = 0; i < sta->sa_query_count; i++) { - if (os_memcmp(sta->sa_query_trans_id + - i * WLAN_SA_QUERY_TR_ID_LEN, - mgmt->u.action.u.sa_query_resp.trans_id, - WLAN_SA_QUERY_TR_ID_LEN) == 0) - break; - } - - if (i >= sta->sa_query_count) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query " - "transaction identifier found"); - return; - } - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "Reply to pending SA Query received"); - ap_sta_stop_sa_query(hapd, sta); + ieee802_11_sa_query_action(hapd, mgmt->sa, + mgmt->u.action.u.sa_query_resp.action, + mgmt->u.action.u.sa_query_resp.trans_id); } @@ -1401,7 +1248,10 @@ static int robust_action_frame(u8 category) static void handle_action(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { +#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) struct sta_info *sta; + sta = ap_get_sta(hapd, mgmt->sa); +#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */ if (len < IEEE80211_HDRLEN + 1) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -1411,7 +1261,6 @@ static void handle_action(struct hostapd_data *hapd, return; } - sta = ap_get_sta(hapd, mgmt->sa); #ifdef CONFIG_IEEE80211W if (sta && (sta->flags & WLAN_STA_MFP) && !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) && @@ -1493,7 +1342,7 @@ static void handle_action(struct hostapd_data *hapd, os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); resp->u.action.category |= 0x80; - hostapd_drv_send_mlme(hapd, resp, len); + hostapd_drv_send_mlme(hapd, resp, len, 0); os_free(resp); } } @@ -1536,6 +1385,11 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff; if (!broadcast && +#ifdef CONFIG_P2P + /* Invitation responses can be sent with the peer MAC as BSSID */ + !((hapd->conf->p2p & P2P_GROUP_OWNER) && + stype == WLAN_FC_STYPE_ACTION) && +#endif /* CONFIG_P2P */ os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) { printf("MGMT: BSSID=" MACSTR " not our address\n", MAC2STR(mgmt->bssid)); @@ -1574,7 +1428,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, handle_disassoc(hapd, mgmt, len); break; case WLAN_FC_STYPE_DEAUTH: - wpa_msg(hapd, MSG_DEBUG, "mgmt::deauth"); + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth"); handle_deauth(hapd, mgmt, len); break; case WLAN_FC_STYPE_ACTION: @@ -1688,14 +1542,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd, * step. */ ap_sta_set_authorized(hapd, sta, 1); - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); -#ifdef ANDROID_BRCM_P2P_PATCH - /* Sending the event to parent is required as SSL listens on parent ctrl iface */ - if(hapd->msg_ctx_parent) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); -#endif /* ANDROID_BRCM_P2P_PATCH */ } if (reassoc) @@ -1722,10 +1568,16 @@ static void handle_assoc_cb(struct hostapd_data *hapd, if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability, sta->supported_rates, sta->supported_rates_len, sta->listen_interval, - sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) { + sta->flags & WLAN_STA_HT ? &ht_cap : NULL, + sta->flags, sta->qosinfo)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, "Could not add STA to kernel driver"); + + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_DISASSOC_AP_BUSY); + + goto fail; } if (sta->flags & WLAN_STA_WDS) @@ -1764,6 +1616,54 @@ static void handle_assoc_cb(struct hostapd_data *hapd, } +static void handle_deauth_cb(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len, int ok) +{ + struct sta_info *sta; + if (mgmt->da[0] & 0x01) + return; + sta = ap_get_sta(hapd, mgmt->da); + if (!sta) { + wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR + " not found", MAC2STR(mgmt->da)); + return; + } + if (ok) + wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth", + MAC2STR(sta->addr)); + else + wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge " + "deauth", MAC2STR(sta->addr)); + + ap_sta_deauth_cb(hapd, sta); +} + + +static void handle_disassoc_cb(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len, int ok) +{ + struct sta_info *sta; + if (mgmt->da[0] & 0x01) + return; + sta = ap_get_sta(hapd, mgmt->da); + if (!sta) { + wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR + " not found", MAC2STR(mgmt->da)); + return; + } + if (ok) + wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc", + MAC2STR(sta->addr)); + else + wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge " + "disassoc", MAC2STR(sta->addr)); + + ap_sta_disassoc_cb(hapd, sta); +} + + /** * ieee802_11_mgmt_cb - Process management frame TX status callback * @hapd: hostapd BSS data structure (the BSS from which the management frame @@ -1796,7 +1696,12 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb"); break; case WLAN_FC_STYPE_DEAUTH: - /* ignore */ + wpa_printf(MSG_DEBUG, "mgmt::deauth cb"); + handle_deauth_cb(hapd, mgmt, len, ok); + break; + case WLAN_FC_STYPE_DISASSOC: + wpa_printf(MSG_DEBUG, "mgmt::disassoc cb"); + handle_disassoc_cb(hapd, mgmt, len, ok); break; case WLAN_FC_STYPE_ACTION: wpa_printf(MSG_DEBUG, "mgmt::action cb"); @@ -1853,6 +1758,55 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, } +void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, + const u8 *data, size_t len, int ack) +{ + struct sta_info *sta; + struct hostapd_iface *iface = hapd->iface; + + sta = ap_get_sta(hapd, dst); + if (sta == NULL && iface->num_bss > 1) { + size_t j; + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + sta = ap_get_sta(hapd, dst); + if (sta) + break; + } + } + if (sta == NULL) + return; + + ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack); +} + + +void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr) +{ + struct sta_info *sta; + struct hostapd_iface *iface = hapd->iface; + + sta = ap_get_sta(hapd, addr); + if (sta == NULL && iface->num_bss > 1) { + size_t j; + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + sta = ap_get_sta(hapd, addr); + if (sta) + break; + } + } + if (sta == NULL) + return; + if (!(sta->flags & WLAN_STA_PENDING_POLL)) + return; + + wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending " + "activity poll", MAC2STR(sta->addr)); + sta->flags &= ~WLAN_STA_PENDING_POLL; +} + + void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, int wds) { diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index 157198c..43042a5 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -62,7 +62,21 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta); void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, const u8 *buf, size_t len, int ack); +void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, + const u8 *data, size_t len, int ack); void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, int wds); +u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, + struct sta_info *sta, u8 *eid); +void ieee802_11_sa_query_action(struct hostapd_data *hapd, + const u8 *sa, const u8 action_type, + const u8 *trans_id); +u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid); +int hostapd_update_time_adv(struct hostapd_data *hapd); +void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr); #endif /* IEEE802_11_H */ diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c index b933263..f3f313d 100644 --- a/src/ap/ieee802_11_auth.c +++ b/src/ap/ieee802_11_auth.c @@ -21,6 +21,7 @@ #include "utils/common.h" #include "utils/eloop.h" +#include "crypto/sha1.h" #include "radius/radius.h" #include "radius/radius_client.h" #include "hostapd.h" @@ -40,6 +41,8 @@ struct hostapd_cached_radius_acl { u32 session_timeout; u32 acct_interim_interval; int vlan_id; + int has_psk; + u8 psk[PMK_LEN]; }; @@ -68,7 +71,8 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache) static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, u32 *session_timeout, - u32 *acct_interim_interval, int *vlan_id) + u32 *acct_interim_interval, int *vlan_id, + u8 *psk, int *has_psk) { struct hostapd_cached_radius_acl *entry; struct os_time now; @@ -89,6 +93,10 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, entry->acct_interim_interval; if (vlan_id) *vlan_id = entry->vlan_id; + if (psk) + os_memcpy(psk, entry->psk, PMK_LEN); + if (has_psk) + *has_psk = entry->has_psk; return entry->accepted; } @@ -210,11 +218,14 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, * @session_timeout: Buffer for returning session timeout (from RADIUS) * @acct_interim_interval: Buffer for returning account interval (from RADIUS) * @vlan_id: Buffer for returning VLAN ID + * @psk: Buffer for returning WPA PSK + * @has_psk: Buffer for indicating whether psk was filled * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING */ 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, int *vlan_id, + u8 *psk, int *has_psk) { if (session_timeout) *session_timeout = 0; @@ -222,6 +233,10 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, *acct_interim_interval = 0; if (vlan_id) *vlan_id = 0; + if (has_psk) + *has_psk = 0; + if (psk) + os_memset(psk, 0, PMK_LEN); if (hostapd_maclist_found(hapd->conf->accept_mac, hapd->conf->num_accept_mac, addr, vlan_id)) @@ -241,11 +256,12 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, return HOSTAPD_ACL_REJECT; #else /* CONFIG_NO_RADIUS */ struct hostapd_acl_query_data *query; + struct os_time t; /* Check whether ACL cache has an entry for this station */ int res = hostapd_acl_cache_get(hapd, addr, session_timeout, acct_interim_interval, - vlan_id); + vlan_id, psk, has_psk); if (res == HOSTAPD_ACL_ACCEPT || res == HOSTAPD_ACL_ACCEPT_TIMEOUT) return res; @@ -271,7 +287,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, wpa_printf(MSG_ERROR, "malloc for query data failed"); return HOSTAPD_ACL_REJECT; } - time(&query->timestamp); + os_get_time(&t); + query->timestamp = t.sec; os_memcpy(query->addr, addr, ETH_ALEN); if (hostapd_radius_acl_query(hapd, addr, query)) { wpa_printf(MSG_DEBUG, "Failed to send Access-Request " @@ -397,6 +414,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, struct hostapd_acl_query_data *query, *prev; struct hostapd_cached_radius_acl *cache; struct radius_hdr *hdr = radius_msg_get_hdr(msg); + struct os_time t; query = hapd->acl_queries; prev = NULL; @@ -431,9 +449,13 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); goto done; } - time(&cache->timestamp); + os_get_time(&t); + cache->timestamp = t.sec; os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { + int passphraselen; + char *passphrase; + if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, &cache->session_timeout) == 0) cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT; @@ -452,6 +474,32 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, } cache->vlan_id = radius_msg_get_vlanid(msg); + + passphrase = radius_msg_get_tunnel_password( + msg, &passphraselen, + hapd->conf->radius->auth_server->shared_secret, + hapd->conf->radius->auth_server->shared_secret_len, + req); + cache->has_psk = passphrase != NULL; + if (passphrase != NULL) { + /* passphrase does not contain the NULL termination. + * Add it here as pbkdf2_sha1 requires it. */ + char *strpassphrase = os_zalloc(passphraselen + 1); + if (strpassphrase) { + os_memcpy(strpassphrase, passphrase, + passphraselen); + pbkdf2_sha1(strpassphrase, + hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len, 4096, + cache->psk, PMK_LEN); + os_free(strpassphrase); + } + os_free(passphrase); + } + + if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED && + cache->psk == NULL) + cache->accepted = HOSTAPD_ACL_REJECT; } else cache->accepted = HOSTAPD_ACL_REJECT; cache->next = hapd->acl_cache; diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h index b2971e5..a90571f 100644 --- a/src/ap/ieee802_11_auth.h +++ b/src/ap/ieee802_11_auth.h @@ -24,7 +24,8 @@ enum { 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, int *vlan_id, + u8 *psk, int *has_psk); int hostapd_acl_init(struct hostapd_data *hapd); void hostapd_acl_deinit(struct hostapd_data *hapd); diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c new file mode 100644 index 0000000..8503fce --- /dev/null +++ b/src/ap/ieee802_11_shared.c @@ -0,0 +1,405 @@ +/* + * hostapd / IEEE 802.11 Management + * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "hostapd.h" +#include "sta_info.h" +#include "ap_config.h" +#include "ap_drv_ops.h" +#include "ieee802_11.h" + + +#ifdef CONFIG_IEEE80211W + +u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, + struct sta_info *sta, u8 *eid) +{ + u8 *pos = eid; + u32 timeout, tu; + struct os_time now, passed; + + *pos++ = WLAN_EID_TIMEOUT_INTERVAL; + *pos++ = 5; + *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; + os_get_time(&now); + os_time_sub(&now, &sta->sa_query_start, &passed); + tu = (passed.sec * 1000000 + passed.usec) / 1024; + if (hapd->conf->assoc_sa_query_max_timeout > tu) + timeout = hapd->conf->assoc_sa_query_max_timeout - tu; + else + timeout = 0; + if (timeout < hapd->conf->assoc_sa_query_max_timeout) + timeout++; /* add some extra time for local timers */ + WPA_PUT_LE32(pos, timeout); + pos += 4; + + return pos; +} + + +/* MLME-SAQuery.request */ +void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, + const u8 *addr, const u8 *trans_id) +{ + struct ieee80211_mgmt mgmt; + u8 *end; + + wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to " + MACSTR, MAC2STR(addr)); + wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", + trans_id, WLAN_SA_QUERY_TR_ID_LEN); + + os_memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memcpy(mgmt.da, addr, ETH_ALEN); + os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); + mgmt.u.action.category = WLAN_ACTION_SA_QUERY; + mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST; + os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id, + WLAN_SA_QUERY_TR_ID_LEN); + end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; + if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0) + perror("ieee802_11_send_sa_query_req: send"); +} + + +static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd, + const u8 *sa, const u8 *trans_id) +{ + struct sta_info *sta; + struct ieee80211_mgmt resp; + u8 *end; + + wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from " + MACSTR, MAC2STR(sa)); + wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", + trans_id, WLAN_SA_QUERY_TR_ID_LEN); + + sta = ap_get_sta(hapd, sa); + if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request " + "from unassociated STA " MACSTR, MAC2STR(sa)); + return; + } + + wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to " + MACSTR, MAC2STR(sa)); + + os_memset(&resp, 0, sizeof(resp)); + resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memcpy(resp.da, sa, ETH_ALEN); + os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN); + os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN); + resp.u.action.category = WLAN_ACTION_SA_QUERY; + resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE; + os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id, + WLAN_SA_QUERY_TR_ID_LEN); + end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; + if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0) + perror("ieee80211_mgmt_sa_query_request: send"); +} + + +void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa, + const u8 action_type, const u8 *trans_id) +{ + struct sta_info *sta; + int i; + + if (action_type == WLAN_SA_QUERY_REQUEST) { + ieee802_11_send_sa_query_resp(hapd, sa, trans_id); + return; + } + + if (action_type != WLAN_SA_QUERY_RESPONSE) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query " + "Action %d", action_type); + return; + } + + wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from " + MACSTR, MAC2STR(sa)); + wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", + trans_id, WLAN_SA_QUERY_TR_ID_LEN); + + /* MLME-SAQuery.confirm */ + + sta = ap_get_sta(hapd, sa); + if (sta == NULL || sta->sa_query_trans_id == NULL) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with " + "pending SA Query request found"); + return; + } + + for (i = 0; i < sta->sa_query_count; i++) { + if (os_memcmp(sta->sa_query_trans_id + + i * WLAN_SA_QUERY_TR_ID_LEN, + trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0) + break; + } + + if (i >= sta->sa_query_count) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query " + "transaction identifier found"); + return; + } + + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "Reply to pending SA Query received"); + ap_sta_stop_sa_query(hapd, sta); +} + +#endif /* CONFIG_IEEE80211W */ + + +u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) +{ + u8 *pos = eid; + u8 len = 0; + + if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) + len = 5; + if (len < 4 && hapd->conf->interworking) + len = 4; + if (len == 0) + return eid; + + *pos++ = WLAN_EID_EXT_CAPAB; + *pos++ = len; + *pos++ = 0x00; + *pos++ = 0x00; + *pos++ = 0x00; + + *pos = 0x00; + if (hapd->conf->time_advertisement == 2) + *pos |= 0x08; /* Bit 27 - UTC TSF Offset */ + if (hapd->conf->interworking) + *pos |= 0x80; /* Bit 31 - Interworking */ + pos++; + + if (len < 5) + return pos; + *pos = 0x00; + if (hapd->conf->tdls & TDLS_PROHIBIT) + *pos |= 0x40; /* Bit 38 - TDLS Prohibited */ + if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) + *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */ + pos++; + + return pos; +} + + +u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid) +{ + u8 *pos = eid; +#ifdef CONFIG_INTERWORKING + u8 *len; + + if (!hapd->conf->interworking) + return eid; + + *pos++ = WLAN_EID_INTERWORKING; + len = pos++; + + *pos = hapd->conf->access_network_type; + if (hapd->conf->internet) + *pos |= INTERWORKING_ANO_INTERNET; + if (hapd->conf->asra) + *pos |= INTERWORKING_ANO_ASRA; + if (hapd->conf->esr) + *pos |= INTERWORKING_ANO_ESR; + if (hapd->conf->uesa) + *pos |= INTERWORKING_ANO_UESA; + pos++; + + if (hapd->conf->venue_info_set) { + *pos++ = hapd->conf->venue_group; + *pos++ = hapd->conf->venue_type; + } + + if (!is_zero_ether_addr(hapd->conf->hessid)) { + os_memcpy(pos, hapd->conf->hessid, ETH_ALEN); + pos += ETH_ALEN; + } + + *len = pos - len - 1; +#endif /* CONFIG_INTERWORKING */ + + return pos; +} + + +u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid) +{ + u8 *pos = eid; +#ifdef CONFIG_INTERWORKING + + /* TODO: Separate configuration for ANQP? */ + if (!hapd->conf->interworking) + return eid; + + *pos++ = WLAN_EID_ADV_PROTO; + *pos++ = 2; + *pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */ + *pos++ = ACCESS_NETWORK_QUERY_PROTOCOL; +#endif /* CONFIG_INTERWORKING */ + + return pos; +} + + +u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid) +{ + u8 *pos = eid; +#ifdef CONFIG_INTERWORKING + u8 *len; + unsigned int i, count; + + if (!hapd->conf->interworking || + hapd->conf->roaming_consortium == NULL || + hapd->conf->roaming_consortium_count == 0) + return eid; + + *pos++ = WLAN_EID_ROAMING_CONSORTIUM; + len = pos++; + + /* Number of ANQP OIs (in addition to the max 3 listed here) */ + if (hapd->conf->roaming_consortium_count > 3 + 255) + *pos++ = 255; + else if (hapd->conf->roaming_consortium_count > 3) + *pos++ = hapd->conf->roaming_consortium_count - 3; + else + *pos++ = 0; + + /* OU #1 and #2 Lengths */ + *pos = hapd->conf->roaming_consortium[0].len; + if (hapd->conf->roaming_consortium_count > 1) + *pos |= hapd->conf->roaming_consortium[1].len << 4; + pos++; + + if (hapd->conf->roaming_consortium_count > 3) + count = 3; + else + count = hapd->conf->roaming_consortium_count; + + for (i = 0; i < count; i++) { + os_memcpy(pos, hapd->conf->roaming_consortium[i].oi, + hapd->conf->roaming_consortium[i].len); + pos += hapd->conf->roaming_consortium[i].len; + } + + *len = pos - len - 1; +#endif /* CONFIG_INTERWORKING */ + + return pos; +} + + +u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid) +{ + if (hapd->conf->time_advertisement != 2) + return eid; + + if (hapd->time_adv == NULL && + hostapd_update_time_adv(hapd) < 0) + return eid; + + if (hapd->time_adv == NULL) + return eid; + + os_memcpy(eid, wpabuf_head(hapd->time_adv), + wpabuf_len(hapd->time_adv)); + eid += wpabuf_len(hapd->time_adv); + + return eid; +} + + +u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid) +{ + size_t len; + + if (hapd->conf->time_advertisement != 2) + return eid; + + len = os_strlen(hapd->conf->time_zone); + + *eid++ = WLAN_EID_TIME_ZONE; + *eid++ = len; + os_memcpy(eid, hapd->conf->time_zone, len); + eid += len; + + return eid; +} + + +int hostapd_update_time_adv(struct hostapd_data *hapd) +{ + const int elen = 2 + 1 + 10 + 5 + 1; + struct os_time t; + struct os_tm tm; + u8 *pos; + + if (hapd->conf->time_advertisement != 2) + return 0; + + if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0) + return -1; + + if (!hapd->time_adv) { + hapd->time_adv = wpabuf_alloc(elen); + if (hapd->time_adv == NULL) + return -1; + pos = wpabuf_put(hapd->time_adv, elen); + } else + pos = wpabuf_mhead_u8(hapd->time_adv); + + *pos++ = WLAN_EID_TIME_ADVERTISEMENT; + *pos++ = 1 + 10 + 5 + 1; + + *pos++ = 2; /* UTC time at which the TSF timer is 0 */ + + /* Time Value at TSF 0 */ + /* FIX: need to calculate this based on the current TSF value */ + WPA_PUT_LE16(pos, tm.year); /* Year */ + pos += 2; + *pos++ = tm.month; /* Month */ + *pos++ = tm.day; /* Day of month */ + *pos++ = tm.hour; /* Hours */ + *pos++ = tm.min; /* Minutes */ + *pos++ = tm.sec; /* Seconds */ + WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */ + pos += 2; + *pos++ = 0; /* Reserved */ + + /* Time Error */ + /* TODO: fill in an estimate on the error */ + *pos++ = 0; + *pos++ = 0; + *pos++ = 0; + *pos++ = 0; + *pos++ = 0; + + *pos++ = hapd->time_update_counter++; + + return 0; +} diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 49eba69..153b271 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -20,13 +20,13 @@ #include "crypto/crypto.h" #include "crypto/random.h" #include "common/ieee802_11_defs.h" -#include "common/wpa_ctrl.h" #include "radius/radius.h" #include "radius/radius_client.h" #include "eap_server/eap.h" #include "eap_common/eap_wsc_common.h" #include "eapol_auth/eapol_auth_sm.h" #include "eapol_auth/eapol_auth_sm_i.h" +#include "p2p/p2p.h" #include "hostapd.h" #include "accounting.h" #include "sta_info.h" @@ -36,9 +36,6 @@ #include "ap_config.h" #include "ap_drv_ops.h" #include "ieee802_1x.h" -#ifdef ANDROID_BRCM_P2P_PATCH -#include "p2p/p2p_i.h" -#endif static void ieee802_1x_finished(struct hostapd_data *hapd, @@ -87,53 +84,16 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized) { int res; -#ifdef ANDROID_BRCM_P2P_PATCH - u8 *dev_addr = NULL; -#endif if (sta->flags & WLAN_STA_PREAUTH) return; if (authorized) { - if (!ap_sta_is_authorized(sta)) { -#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_P2P) - if((dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr))) - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_CONNECTED MACSTR " dev_addr="MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr)); - else -#endif /*ANDROID_BRCM_P2P_PATCH*/ - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); - -#ifdef ANDROID_BRCM_P2P_PATCH - /* Sending the event to parent is required as SSL listens on parent ctrl iface */ - if(hapd->msg_ctx_parent) { - if(dev_addr) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_CONNECTED MACSTR " dev_addr="MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr)); - else - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_CONNECTED MACSTR , MAC2STR(sta->addr)); - } -#endif /* ANDROID_BRCM_P2P_PATCH */ - } - ap_sta_set_authorized(hapd, sta, 1); res = hostapd_set_authorized(hapd, sta, 1); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "authorizing port"); } else { - if (ap_sta_is_authorized(sta) && (sta->flags & WLAN_STA_ASSOC)) { - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#ifdef ANDROID_BRCM_P2P_PATCH - if(hapd->msg_ctx_parent) - wpa_msg(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); -#endif /* ANDROID_BRCM_P2P_PATCH */ - } ap_sta_set_authorized(hapd, sta, 0); res = hostapd_set_authorized(hapd, sta, 0); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, @@ -722,7 +682,8 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, (unsigned long) len, MAC2STR(sa)); sta = ap_get_sta(hapd, sa); - if (!sta || !(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH))) { + if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && + !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " "associated/Pre-authenticating STA"); return; @@ -785,14 +746,24 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, return; #ifdef CONFIG_WPS - if (!hapd->conf->ieee802_1x && - ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == - WLAN_STA_MAYBE_WPS)) { - /* - * Delay EAPOL frame transmission until a possible WPS - * STA initiates the handshake with EAPOL-Start. - */ - sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; + if (!hapd->conf->ieee802_1x) { + u32 wflags = sta->flags & (WLAN_STA_WPS | + WLAN_STA_WPS2 | + WLAN_STA_MAYBE_WPS); + if (wflags == WLAN_STA_MAYBE_WPS || + wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { + /* + * Delay EAPOL frame transmission until a + * possible WPS STA initiates the handshake + * with EAPOL-Start. Only allow the wait to be + * skipped if the STA is known to support WPS + * 2.0. + */ + wpa_printf(MSG_DEBUG, "WPS: Do not start " + "EAPOL until EAPOL-Start is " + "received"); + sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; + } } #endif /* CONFIG_WPS */ @@ -921,11 +892,14 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) #ifdef CONFIG_WPS sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; - if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) { + if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) { /* - * Delay EAPOL frame transmission until a possible WPS - * initiates the handshake with EAPOL-Start. + * Delay EAPOL frame transmission until a possible WPS STA + * initiates the handshake with EAPOL-Start. Only allow the + * wait to be skipped if the STA is known to support WPS 2.0. */ + wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until " + "EAPOL-Start is received"); sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; } #endif /* CONFIG_WPS */ @@ -1443,6 +1417,9 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) * request and we cannot continue EAP processing (EAP-Failure * could only be sent if the EAP peer actually replied). */ + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR, + MAC2STR(sta->addr)); + sm->eap_if->portEnabled = FALSE; ap_sta_disconnect(hapd, sta, sta->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); @@ -1595,7 +1572,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, { struct hostapd_data *hapd = ctx; const struct hostapd_eap_user *eap_user; - int i, count; + int i; eap_user = hostapd_get_eap_user(hapd->conf, identity, identity_len, phase2); @@ -1604,10 +1581,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, os_memset(user, 0, sizeof(*user)); user->phase2 = phase2; - count = EAP_USER_MAX_METHODS; - if (count > EAP_MAX_METHODS) - count = EAP_MAX_METHODS; - for (i = 0; i < count; i++) { + for (i = 0; i < EAP_MAX_METHODS; i++) { user->methods[i].vendor = eap_user->methods[i].vendor; user->methods[i].method = eap_user->methods[i].method; } @@ -1619,6 +1593,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, os_memcpy(user->password, eap_user->password, eap_user->password_len); user->password_len = eap_user->password_len; + user->password_hash = eap_user->password_hash; } user->force_version = eap_user->force_version; user->ttls_auth = eap_user->ttls_auth; @@ -1795,15 +1770,13 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, const u8 *buf, size_t len, int ack) { struct ieee80211_hdr *hdr; - struct ieee802_1x_hdr *xhdr; - struct ieee802_1x_eapol_key *key; u8 *pos; const unsigned char rfc1042_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; if (sta == NULL) return -1; - if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr)) + if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2) return 0; hdr = (struct ieee80211_hdr *) buf; @@ -1815,16 +1788,30 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, return 0; pos += 2; - xhdr = (struct ieee802_1x_hdr *) pos; - pos += sizeof(*xhdr); + return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos, + ack); +} + + +int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *buf, int len, int ack) +{ + const struct ieee802_1x_hdr *xhdr = + (const struct ieee802_1x_hdr *) buf; + const u8 *pos = buf + sizeof(*xhdr); + struct ieee802_1x_eapol_key *key; + if (len < (int) sizeof(*xhdr)) + return 0; wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " "type=%d length=%d - ack=%d", MAC2STR(sta->addr), xhdr->version, xhdr->type, be_to_host16(xhdr->length), ack); - if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && - pos + sizeof(struct wpa_eapol_key) <= buf + len) { + if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) + return 0; + + if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { const struct wpa_eapol_key *wpa; wpa = (const struct wpa_eapol_key *) pos; if (wpa->type == EAPOL_KEY_TYPE_RSN || @@ -1835,11 +1822,10 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant * or Authenticator state machines, but EAPOL-Key packets are not - * retransmitted in case of failure. Try to re-sent failed EAPOL-Key + * retransmitted in case of failure. Try to re-send failed EAPOL-Key * packets couple of times because otherwise STA keys become * unsynchronized with AP. */ - if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack && - pos + sizeof(*key) <= buf + len) { + if (!ack && pos + sizeof(*key) <= buf + len) { key = (struct ieee802_1x_eapol_key *) pos; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " @@ -1943,6 +1929,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, { int len = 0, ret; struct eapol_state_machine *sm = sta->eapol_sm; + struct os_time t; if (sm == NULL) return 0; @@ -2057,6 +2044,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, len += ret; /* dot1xAuthSessionStatsTable */ + os_get_time(&t); ret = os_snprintf(buf + len, buflen - len, /* TODO: dot1xAuthSessionOctetsRx */ /* TODO: dot1xAuthSessionOctetsTx */ @@ -2071,8 +2059,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, (wpa_key_mgmt_wpa_ieee8021x( wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 1 : 2, - (unsigned int) (time(NULL) - - sta->acct_session_start), + (unsigned int) (t.sec - sta->acct_session_start), sm->identity); if (ret < 0 || (size_t) ret >= buflen - len) return len; @@ -2099,22 +2086,25 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, "Added PMKSA cache entry (IEEE 802.1X)"); } -#ifdef CONFIG_WPS - if (!success && (sta->flags & WLAN_STA_WPS)) { + if (!success) { /* * Many devices require deauthentication after WPS provisioning * and some may not be be able to do that themselves, so - * disconnect the client here. + * disconnect the client here. In addition, this may also + * benefit IEEE 802.1X/EAPOL authentication cases, too since + * the EAPOL PAE state machine would remain in HELD state for + * considerable amount of time and some EAP methods, like + * EAP-FAST with anonymous provisioning, may require another + * EAPOL authentication to be started to complete connection. */ - wpa_printf(MSG_DEBUG, "WPS: Force disconnection after " - "EAP-Failure"); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force " + "disconnection after EAP-Failure"); /* Add a small sleep to increase likelihood of previously * requested EAP-Failure TX getting out before this should the * driver reorder operations. */ os_sleep(0, 10000); ap_sta_disconnect(hapd, sta, sta->addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); + WLAN_REASON_IEEE_802_1X_AUTH_FAILED); } -#endif /* CONFIG_WPS */ } diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h index 1a4d2eb..267e22a 100644 --- a/src/ap/ieee802_1x.h +++ b/src/ap/ieee802_1x.h @@ -68,6 +68,8 @@ int ieee802_1x_init(struct hostapd_data *hapd); void ieee802_1x_deinit(struct hostapd_data *hapd); int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, const u8 *buf, size_t len, int ack); +int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *data, int len, int ack); u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len); u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, int idx); diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index e829447..972a723 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -1,6 +1,6 @@ /* * hostapd / Station table - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,6 +17,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "common/ieee802_11_defs.h" +#include "common/wpa_ctrl.h" #include "radius/radius.h" #include "radius/radius_client.h" #include "drivers/driver.h" @@ -38,9 +39,12 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, struct sta_info *sta); static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx); +static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx); +static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx); #ifdef CONFIG_IEEE80211W static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx); #endif /* CONFIG_IEEE80211W */ +static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta); int ap_for_each_sta(struct hostapd_data *hapd, int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, @@ -198,6 +202,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); + eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); + eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); ieee802_1x_free_station(sta); wpa_auth_sta_deinit(sta->wpa_sm); @@ -222,6 +228,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) wpabuf_free(sta->p2p_ie); os_free(sta->ht_capabilities); + os_free(sta->psk); os_free(sta); } @@ -275,31 +282,37 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) int inactive_sec; inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr); if (inactive_sec == -1) { - wpa_msg(hapd, MSG_DEBUG, "Check inactivity: Could not " + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "Check inactivity: Could not " "get station info rom kernel driver for " MACSTR, MAC2STR(sta->addr)); } else if (inactive_sec < hapd->conf->ap_max_inactivity && sta->flags & WLAN_STA_ASSOC) { /* station activity detected; reset timeout state */ - wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been " - "active %is ago", + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "Station " MACSTR " has been active %is ago", MAC2STR(sta->addr), inactive_sec); sta->timeout_next = STA_NULLFUNC; next_time = hapd->conf->ap_max_inactivity - inactive_sec; } else { - wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been " + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "Station " MACSTR " has been " "inactive too long: %d sec, max allowed: %d", MAC2STR(sta->addr), inactive_sec, hapd->conf->ap_max_inactivity); + + if (hapd->conf->skip_inactivity_poll) + sta->timeout_next = STA_DISASSOC; } } if ((sta->flags & WLAN_STA_ASSOC) && sta->timeout_next == STA_DISASSOC && - !(sta->flags & WLAN_STA_PENDING_POLL)) { - wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has ACKed data " - "poll", MAC2STR(sta->addr)); + !(sta->flags & WLAN_STA_PENDING_POLL) && + !hapd->conf->skip_inactivity_poll) { + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR + " has ACKed data poll", MAC2STR(sta->addr)); /* data nullfunc frame poll did not produce TX errors; assume * station ACKed it */ sta->timeout_next = STA_NULLFUNC; @@ -314,46 +327,17 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) if (sta->timeout_next == STA_NULLFUNC && (sta->flags & WLAN_STA_ASSOC)) { -#ifndef CONFIG_NATIVE_WINDOWS - /* send data frame to poll STA and check whether this frame - * is ACKed */ - struct ieee80211_hdr hdr; - - wpa_printf(MSG_DEBUG, " Polling STA with data frame"); + wpa_printf(MSG_DEBUG, " Polling STA"); sta->flags |= WLAN_STA_PENDING_POLL; - - os_memset(&hdr, 0, sizeof(hdr)); - if (hapd->driver && - os_strcmp(hapd->driver->name, "hostap") == 0) { - /* - * WLAN_FC_STYPE_NULLFUNC would be more appropriate, - * but it is apparently not retried so TX Exc events - * are not received for it. - */ - hdr.frame_control = - IEEE80211_FC(WLAN_FC_TYPE_DATA, - WLAN_FC_STYPE_DATA); - } else { - hdr.frame_control = - IEEE80211_FC(WLAN_FC_TYPE_DATA, - WLAN_FC_STYPE_NULLFUNC); - } - - hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS); - os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN); - os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr, - ETH_ALEN); - os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN); - - if (hostapd_drv_send_mlme(hapd, &hdr, sizeof(hdr)) < 0) - perror("ap_handle_timer: send"); -#endif /* CONFIG_NATIVE_WINDOWS */ + hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr, + sta->flags & WLAN_STA_WMM); } else if (sta->timeout_next != STA_REMOVE) { int deauth = sta->timeout_next == STA_DEAUTH; - wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR, - deauth ? "deauthentication" : "disassociation", - MAC2STR(sta->addr)); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, + "Timeout, sending %s info to STA " MACSTR, + deauth ? "deauthentication" : "disassociation", + MAC2STR(sta->addr)); if (deauth) { hostapd_drv_sta_deauth( @@ -373,6 +357,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) hapd, sta); break; case STA_DISASSOC: + ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~WLAN_STA_ASSOC; ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); if (!sta->acct_terminate_cause) @@ -393,7 +378,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) case STA_REMOVE: hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "deauthenticated due to " - "inactivity"); + "inactivity (timer DEAUTH/REMOVE)"); if (!sta->acct_terminate_cause) sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; @@ -525,13 +510,23 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, } +static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct sta_info *sta = timeout_ctx; + + ap_sta_remove(hapd, sta); + mlme_disassociate_indication(hapd, sta, sta->disassoc_reason); +} + + void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, u16 reason) { wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR, hapd->conf->iface, MAC2STR(sta->addr)); sta->flags &= ~WLAN_STA_ASSOC; - ap_sta_remove(hapd, sta); + ap_sta_set_authorized(hapd, sta, 0); sta->timeout_next = STA_DEAUTH; eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0, @@ -539,7 +534,22 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); - mlme_disassociate_indication(hapd, sta, reason); + sta->disassoc_reason = reason; + sta->flags |= WLAN_STA_PENDING_DISASSOC_CB; + eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); + eloop_register_timeout(hapd->iface->drv_flags & + WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, + ap_sta_disassoc_cb_timeout, hapd, sta); +} + + +static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct sta_info *sta = timeout_ctx; + + ap_sta_remove(hapd, sta); + mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason); } @@ -549,7 +559,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR, hapd->conf->iface, MAC2STR(sta->addr)); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - ap_sta_remove(hapd, sta); + ap_sta_set_authorized(hapd, sta, 0); sta->timeout_next = STA_REMOVE; eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, @@ -557,7 +567,12 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); - mlme_deauthenticate_indication(hapd, sta, reason); + sta->deauth_reason = reason; + sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; + eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); + eloop_register_timeout(hapd->iface->drv_flags & + WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, + ap_sta_deauth_cb_timeout, hapd, sta); } @@ -762,17 +777,58 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta) void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized) { + const u8 *dev_addr = NULL; if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) return; - if (authorized) +#ifdef CONFIG_P2P + dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr); +#endif /* CONFIG_P2P */ + + if (authorized) { + if (dev_addr) + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED + MACSTR " p2p_dev_addr=" MACSTR, + MAC2STR(sta->addr), MAC2STR(dev_addr)); + else + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED + MACSTR, MAC2STR(sta->addr)); + if (hapd->msg_ctx_parent && + hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr) + wpa_msg(hapd->msg_ctx_parent, MSG_INFO, + AP_STA_CONNECTED MACSTR " p2p_dev_addr=" + MACSTR, + MAC2STR(sta->addr), MAC2STR(dev_addr)); + else if (hapd->msg_ctx_parent && + hapd->msg_ctx_parent != hapd->msg_ctx) + wpa_msg(hapd->msg_ctx_parent, MSG_INFO, + AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); + sta->flags |= WLAN_STA_AUTHORIZED; - else + } else { + if (dev_addr) + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED + MACSTR " p2p_dev_addr=" MACSTR, + MAC2STR(sta->addr), MAC2STR(dev_addr)); + else + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED + MACSTR, MAC2STR(sta->addr)); + if (hapd->msg_ctx_parent && + hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr) + wpa_msg(hapd->msg_ctx_parent, MSG_INFO, + AP_STA_DISCONNECTED MACSTR " p2p_dev_addr=" + MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr)); + else if (hapd->msg_ctx_parent && + hapd->msg_ctx_parent != hapd->msg_ctx) + wpa_msg(hapd->msg_ctx_parent, MSG_INFO, + AP_STA_DISCONNECTED MACSTR, + MAC2STR(sta->addr)); sta->flags &= ~WLAN_STA_AUTHORIZED; + } if (hapd->sta_authorized_cb) hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx, - sta->addr, authorized); + sta->addr, authorized, dev_addr); } @@ -791,6 +847,38 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta); + eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, + ap_handle_timer, hapd, sta); sta->timeout_next = STA_REMOVE; + + sta->deauth_reason = reason; + sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; + eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); + eloop_register_timeout(hapd->iface->drv_flags & + WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, + ap_sta_deauth_cb_timeout, hapd, sta); +} + + +void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta) +{ + if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) { + wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame"); + return; + } + sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB; + eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); + ap_sta_deauth_cb_timeout(hapd, sta); +} + + +void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta) +{ + if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) { + wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame"); + return; + } + sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB; + eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); + ap_sta_disassoc_cb_timeout(hapd, sta); } diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 9ec4fe3..daa96bf 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -1,6 +1,6 @@ /* * hostapd / Station table - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -32,6 +32,9 @@ #define WLAN_STA_MAYBE_WPS BIT(13) #define WLAN_STA_WDS BIT(14) #define WLAN_STA_ASSOC_REQ_OK BIT(15) +#define WLAN_STA_WPS2 BIT(16) +#define WLAN_STA_PENDING_DISASSOC_CB BIT(29) +#define WLAN_STA_PENDING_DEAUTH_CB BIT(30) #define WLAN_STA_NONERP BIT(31) /* Maximum number of supported rates (from both Supported Rates and Extended @@ -49,6 +52,7 @@ struct sta_info { u16 listen_interval; /* or beacon_int for APs */ u8 supported_rates[WLAN_SUPP_RATES_MAX]; int supported_rates_len; + u8 qosinfo; /* Valid when WLAN_STA_WMM is set */ unsigned int nonerp_set:1; unsigned int no_short_slot_time_set:1; @@ -65,6 +69,9 @@ struct sta_info { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE } timeout_next; + u16 deauth_reason; + u16 disassoc_reason; + /* IEEE 802.1X related data */ struct eapol_state_machine *eapol_sm; @@ -92,6 +99,7 @@ struct sta_info { struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */ int vlan_id; + u8 *psk; /* PSK from RADIUS authentication server */ struct ieee80211_ht_capabilities *ht_capabilities; @@ -114,7 +122,7 @@ struct sta_info { * passed since last received frame from the station, a nullfunc data frame is * sent to the station. If this frame is not acknowledged and no other frames * have been received, the station will be disassociated after - * AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated + * 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) @@ -162,4 +170,7 @@ static inline int ap_sta_is_authorized(struct sta_info *sta) return sta->flags & WLAN_STA_AUTHORIZED; } +void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta); +void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta); + #endif /* STA_INFO_H */ diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c index 1925217..fac7f4b 100644 --- a/src/ap/tkip_countermeasures.c +++ b/src/ap/tkip_countermeasures.c @@ -1,6 +1,6 @@ /* * hostapd / TKIP countermeasures - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -60,9 +60,15 @@ static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd) } +void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd) +{ + eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL); +} + + void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) { - time_t now; + struct os_time now; if (addr && local) { struct sta_info *sta = ap_get_sta(hapd, addr); @@ -82,13 +88,13 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) } } - time(&now); - if (now > hapd->michael_mic_failure + 60) { + os_get_time(&now); + if (now.sec > hapd->michael_mic_failure + 60) { hapd->michael_mic_failures = 1; } else { hapd->michael_mic_failures++; if (hapd->michael_mic_failures > 1) ieee80211_tkip_countermeasures_start(hapd); } - hapd->michael_mic_failure = now; + hapd->michael_mic_failure = now.sec; } diff --git a/src/ap/tkip_countermeasures.h b/src/ap/tkip_countermeasures.h index 5a1afce..a8ffd16 100644 --- a/src/ap/tkip_countermeasures.h +++ b/src/ap/tkip_countermeasures.h @@ -1,6 +1,6 @@ /* * hostapd / TKIP countermeasures - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,5 +16,6 @@ #define TKIP_COUNTERMEASURES_H void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local); +void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd); #endif /* TKIP_COUNTERMEASURES_H */ diff --git a/src/ap/utils.c b/src/ap/utils.c index 0ff48ae..09bc32f 100644 --- a/src/ap/utils.c +++ b/src/ap/utils.c @@ -22,6 +22,7 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd, int (*cb)(void *ctx, const u8 *sa, + const u8 *da, const u8 *bssid, const u8 *ie, size_t ie_len), void *ctx) { diff --git a/src/ap/wmm.c b/src/ap/wmm.c index a6d9b89..d21c82f 100644 --- a/src/ap/wmm.c +++ b/src/ap/wmm.c @@ -72,7 +72,8 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) wmm->version = WMM_VERSION; wmm->qos_info = hapd->parameter_set_count & 0xf; - if (hapd->conf->wmm_uapsd) + if (hapd->conf->wmm_uapsd && + (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD)) wmm->qos_info |= 0x80; wmm->reserved = 0; @@ -97,9 +98,11 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) } -/* This function is called when a station sends an association request with - * WMM info element. The function returns zero on success or non-zero on any - * error in WMM element. eid does not include Element ID and Length octets. */ +/* + * This function is called when a station sends an association request with + * WMM info element. The function returns 1 on success or 0 on any error in WMM + * element. eid does not include Element ID and Length octets. + */ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len) { struct wmm_information_element *wmm; @@ -109,7 +112,7 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len) if (len < sizeof(struct wmm_information_element)) { wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)", (unsigned long) len); - return -1; + return 0; } wmm = (struct wmm_information_element *) eid; @@ -120,10 +123,10 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len) if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT || wmm->version != WMM_VERSION) { wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version"); - return -1; + return 0; } - return 0; + return 1; } @@ -153,7 +156,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr, os_memcpy(t, tspec, sizeof(struct wmm_tspec_element)); len = ((u8 *) (t + 1)) - buf; - if (hostapd_drv_send_mlme(hapd, m, len) < 0) + if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0) perror("wmm_send_action: send"); } diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 0836887..adc69e2 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -1,6 +1,6 @@ /* - * hostapd - IEEE 802.11i-2004 / WPA Authenticator - * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> + * IEEE 802.11 RSN / WPA Authenticator + * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -52,6 +52,7 @@ static const u32 dot11RSNAConfigGroupUpdateCount = 4; static const u32 dot11RSNAConfigPairwiseUpdateCount = 4; static const u32 eapol_key_timeout_first = 100; /* ms */ static const u32 eapol_key_timeout_subseq = 1000; /* ms */ +static const u32 eapol_key_timeout_first_group = 500; /* ms */ /* TODO: make these configurable */ static const int dot11RSNAConfigPMKLifetime = 43200; @@ -194,6 +195,7 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth, { if (wpa_auth->cb.disconnect == NULL) return; + wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr)); wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); } @@ -332,7 +334,7 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth, static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, - int vlan_id) + int vlan_id, int delay_init) { struct wpa_group *group; @@ -349,10 +351,6 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool " "for secure operations - update keys later when " "the first station connects"); -#ifdef ANDROID_BRCM_P2P_PATCH - os_free(group); - return NULL; -#endif } /* @@ -369,9 +367,15 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, } group->GInit = TRUE; - wpa_group_sm_step(wpa_auth, group); - group->GInit = FALSE; - wpa_group_sm_step(wpa_auth, group); + if (delay_init) { + wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start " + "until Beacon frames have been configured"); + /* Initialization is completed in wpa_init_keys(). */ + } else { + wpa_group_sm_step(wpa_auth, group); + group->GInit = FALSE; + wpa_group_sm_step(wpa_auth, group); + } return group; } @@ -403,7 +407,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr, return NULL; } - wpa_auth->group = wpa_group_init(wpa_auth, 0); + wpa_auth->group = wpa_group_init(wpa_auth, 0, 1); if (wpa_auth->group == NULL) { os_free(wpa_auth->wpa_ie); os_free(wpa_auth); @@ -444,6 +448,19 @@ struct wpa_authenticator * wpa_init(const u8 *addr, } +int wpa_init_keys(struct wpa_authenticator *wpa_auth) +{ + struct wpa_group *group = wpa_auth->group; + + wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial " + "keys"); + wpa_group_sm_step(wpa_auth, group); + group->GInit = FALSE; + wpa_group_sm_step(wpa_auth, group); + return 0; +} + + /** * wpa_deinit - Deinitialize WPA authenticator * @wpa_auth: Pointer to WPA authenticator data from wpa_init() @@ -695,6 +712,37 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth, #endif /* CONFIG_IEEE80211R */ +static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int group) +{ + /* Supplicant reported a Michael MIC error */ + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + "received EAPOL-Key Error Request " + "(STA detected Michael MIC failure (group=%d))", + group); + + if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + "ignore Michael MIC failure report since " + "group cipher is not TKIP"); + } else if (!group && sm->pairwise != WPA_CIPHER_TKIP) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + "ignore Michael MIC failure report since " + "pairwise cipher is not TKIP"); + } else { + wpa_auth_mic_failure_report(wpa_auth, sm->addr); + sm->dot11RSNAStatsTKIPRemoteMICFailures++; + wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++; + } + + /* + * Error report is not a request for a new key handshake, but since + * Authenticator may do it, let's change the keys now anyway. + */ + wpa_request_new_ptk(sm); +} + + void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, u8 *data, size_t data_len) @@ -720,6 +768,9 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, key = (struct wpa_eapol_key *) (hdr + 1); key_info = WPA_GET_BE16(key->key_info); key_data_length = WPA_GET_BE16(key->key_data_length); + wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR + " key_info=0x%x type=%u key_data_length=%u", + MAC2STR(sm->addr), key_info, key->type, key_data_length); if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) { wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - " "key_data overflow (%d > %lu)", @@ -819,7 +870,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, if (!(key_info & WPA_KEY_INFO_REQUEST) && !wpa_replay_counter_valid(sm, key->replay_counter)) { int i; - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, "received EAPOL-Key %s with unexpected " "replay counter", msgtxt); for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { @@ -1000,17 +1051,9 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, #endif /* CONFIG_PEERKEY */ return; } else if (key_info & WPA_KEY_INFO_ERROR) { - /* Supplicant reported a Michael MIC error */ - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key Error Request " - "(STA detected Michael MIC failure)"); - wpa_auth_mic_failure_report(wpa_auth, sm->addr); - sm->dot11RSNAStatsTKIPRemoteMICFailures++; - wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++; - /* Error report is not a request for a new key - * handshake, but since Authenticator may do it, let's - * change the keys now anyway. */ - wpa_request_new_ptk(sm); + wpa_receive_error_report( + wpa_auth, sm, + !(key_info & WPA_KEY_INFO_KEY_TYPE)); } else if (key_info & WPA_KEY_INFO_KEY_TYPE) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key Request for new " @@ -1028,9 +1071,6 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key Request for GTK " "rekeying"); - /* FIX: why was this triggering PTK rekeying for the - * STA that requested Group Key rekeying?? */ - /* wpa_request_new_ptk(sta->wpa_sm); */ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); wpa_rekey_gtk(wpa_auth, NULL); } @@ -1057,6 +1097,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, os_memcpy(sm->last_rx_eapol_key, data, data_len); sm->last_rx_eapol_key_len = data_len; + sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE); sm->EAPOLKeyReceived = TRUE; sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE); sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST); @@ -1293,7 +1334,8 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr; if (ctr == 1 && wpa_auth->conf.tx_status) - timeout_ms = eapol_key_timeout_first; + timeout_ms = pairwise ? eapol_key_timeout_first : + eapol_key_timeout_first_group; else timeout_ms = eapol_key_timeout_subseq; if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC)) @@ -1844,6 +1886,20 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) gtk_len = 0; keyidx = 0; _rsc = NULL; + if (sm->rx_eapol_key_secure) { + /* + * It looks like Windows 7 supplicant tries to use + * Secure bit in msg 2/4 after having reported Michael + * MIC failure and it then rejects the 4-way handshake + * if msg 3/4 does not set Secure bit. Work around this + * by setting the Secure bit here even in the case of + * WPA if the supplicant used it first. + */ + wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + "STA used Secure bit in WPA msg 2/4 - " + "set Secure for 3/4 as workaround"); + secure = 1; + } } kde_len = wpa_ie_len + ieee80211w_kde_len(sm); @@ -2469,6 +2525,7 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth) group->GN_igtk = tmp; #endif /* CONFIG_IEEE80211W */ wpa_gtk_update(wpa_auth, group); + wpa_group_config_group_keys(wpa_auth, group); } } @@ -2771,7 +2828,7 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id) wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d", vlan_id); - group = wpa_group_init(wpa_auth, vlan_id); + group = wpa_group_init(wpa_auth, vlan_id, 0); if (group == NULL) return NULL; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index e533a14..ce2751e 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -208,6 +208,7 @@ struct wpa_auth_callbacks { struct wpa_authenticator * wpa_init(const u8 *addr, struct wpa_auth_config *conf, struct wpa_auth_callbacks *cb); +int wpa_init_keys(struct wpa_authenticator *wpa_auth); void wpa_deinit(struct wpa_authenticator *wpa_auth); int wpa_reconfig(struct wpa_authenticator *wpa_auth, struct wpa_auth_config *conf); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 65f5f4c..2d1bbe4 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -24,33 +24,10 @@ #include "wmm.h" #include "wpa_auth.h" #include "wpa_auth_i.h" -#include "wpa_auth_ie.h" #ifdef CONFIG_IEEE80211R -struct wpa_ft_ies { - const u8 *mdie; - size_t mdie_len; - const u8 *ftie; - size_t ftie_len; - const u8 *r1kh_id; - const u8 *gtk; - size_t gtk_len; - const u8 *r0kh_id; - size_t r0kh_id_len; - const u8 *rsn; - size_t rsn_len; - const u8 *rsn_pmkid; - const u8 *ric; - size_t ric_len; -}; - - -static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, - struct wpa_ft_ies *parse); - - static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst, const u8 *data, size_t data_len) { @@ -728,143 +705,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, } -static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, - struct wpa_ft_ies *parse) -{ - const u8 *end, *pos; - - parse->ftie = ie; - parse->ftie_len = ie_len; - - pos = ie + sizeof(struct rsn_ftie); - end = ie + ie_len; - - while (pos + 2 <= end && pos + 2 + pos[1] <= end) { - switch (pos[0]) { - 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]); - return -1; - } - parse->r1kh_id = pos + 2; - break; - case FTIE_SUBELEM_GTK: - parse->gtk = pos + 2; - parse->gtk_len = pos[1]; - 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]); - return -1; - } - parse->r0kh_id = pos + 2; - parse->r0kh_id_len = pos[1]; - break; - } - - pos += 2 + pos[1]; - } - - return 0; -} - - -static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, - struct wpa_ft_ies *parse) -{ - const u8 *end, *pos; - struct wpa_ie_data data; - int ret; - const struct rsn_ftie *ftie; - int prot_ie_count = 0; - - os_memset(parse, 0, sizeof(*parse)); - if (ies == NULL) - return 0; - - pos = ies; - end = ies + ies_len; - while (pos + 2 <= end && pos + 2 + pos[1] <= end) { - switch (pos[0]) { - case WLAN_EID_RSN: - parse->rsn = pos + 2; - parse->rsn_len = pos[1]; - ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, - parse->rsn_len + 2, - &data); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to parse " - "RSN IE: %d", ret); - return -1; - } - if (data.num_pmkid == 1 && data.pmkid) - parse->rsn_pmkid = data.pmkid; - break; - case WLAN_EID_MOBILITY_DOMAIN: - parse->mdie = pos + 2; - parse->mdie_len = pos[1]; - break; - case WLAN_EID_FAST_BSS_TRANSITION: - if (pos[1] < sizeof(*ftie)) - return -1; - ftie = (const struct rsn_ftie *) (pos + 2); - prot_ie_count = ftie->mic_control[1]; - if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) - return -1; - break; - case WLAN_EID_RIC_DATA: - if (parse->ric == NULL) - parse->ric = pos; - } - - pos += 2 + pos[1]; - } - - if (prot_ie_count == 0) - return 0; /* no MIC */ - - /* - * Check that the protected IE count matches with IEs included in the - * frame. - */ - if (parse->rsn) - prot_ie_count--; - if (parse->mdie) - prot_ie_count--; - if (parse->ftie) - prot_ie_count--; - if (prot_ie_count < 0) { - wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " - "the protected IE count"); - return -1; - } - - if (prot_ie_count == 0 && parse->ric) { - wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " - "included in protected IE count"); - return -1; - } - - /* 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]; - } - 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); - return -1; - } - - return 0; -} - - static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, int vlan_id, enum wpa_alg alg, const u8 *addr, int idx, @@ -1207,7 +1047,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, count = 3; if (parse.ric) - count++; + count += ieee802_11_ie_count(parse.ric, parse.ric_len); if (ftie->mic_control[1] != count) { wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " "Control: received %u expected %u", diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 0e3cb31..56bab23 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -29,11 +29,13 @@ #include "ap_drv_ops.h" #include "ap_config.h" #include "wpa_auth.h" +#include "wpa_auth_glue.h" static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, struct wpa_auth_config *wconf) { + os_memset(wconf, 0, sizeof(*wconf)); wconf->wpa = conf->wpa; wconf->wpa_key_mgmt = conf->wpa_key_mgmt; wconf->wpa_pairwise = conf->wpa_pairwise; @@ -184,6 +186,9 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk) { struct hostapd_data *hapd = ctx; + struct sta_info *sta = ap_get_sta(hapd, addr); + if (sta && sta->psk) + return sta->psk; return hostapd_get_psk(hapd->conf, addr, prev_psk); } @@ -384,7 +389,7 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto, ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf, sizeof(*buf) + data_len); os_free(buf); - return -1; + return ret; } @@ -414,7 +419,7 @@ static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst, os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); os_memcpy(&m->u, data, data_len); - res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen); + res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0); os_free(m); return res; } @@ -547,6 +552,7 @@ void hostapd_reconfig_wpa(struct hostapd_data *hapd) void hostapd_deinit_wpa(struct hostapd_data *hapd) { + ieee80211_tkip_countermeasures_deinit(hapd); rsn_preauth_iface_deinit(hapd); if (hapd->wpa_auth) { wpa_deinit(hapd->wpa_auth); diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index 67a5c3b..d82192a 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -86,6 +86,7 @@ struct wpa_state_machine { unsigned int pending_deinit:1; unsigned int started:1; unsigned int mgmt_frame_prot:1; + unsigned int rx_eapol_key_secure:1; #ifdef CONFIG_IEEE80211R unsigned int ft_completed:1; unsigned int pmk_r1_name_valid:1; diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 9d4aa67..4db04bb 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -253,19 +253,10 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, capab |= WPA_CAPABILITY_PREAUTH; if (conf->peerkey) capab |= WPA_CAPABILITY_PEERKEY_ENABLED; -#ifdef ANDROID_BRCM_P2P_PATCH - /* WAR: we should make an get_wpa_rsnie_cap() to get the cap of peer supp - * Temporally we force tp set replay counter tp 0x3 - * as if wmm is enable in all of supp device - */ - capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); -#else if (conf->wmm_enabled) { /* 4 PTKSA replay counters when using WMM */ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } -#endif /* ANDROID_BRCM_P2P_PATCH */ - #ifdef CONFIG_IEEE80211W if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; @@ -350,8 +341,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) pos += res; } #ifdef CONFIG_IEEE80211R - if (wpa_auth->conf.wpa_key_mgmt & - (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) { + if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) { res = wpa_write_mdie(&wpa_auth->conf, pos, buf + sizeof(buf) - pos); if (res < 0) diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 640e8cd..817012e 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -41,7 +41,8 @@ static int hostapd_wps_upnp_init(struct hostapd_data *hapd, static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd); #endif /* CONFIG_WPS_UPNP */ -static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, +static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da, + const u8 *bssid, const u8 *ie, size_t ie_len); static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); @@ -140,7 +141,8 @@ static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie, hapd->wps_beacon_ie = beacon_ie; wpabuf_free(hapd->wps_probe_resp_ie); hapd->wps_probe_resp_ie = probe_resp_ie; - ieee802_11_set_beacon(hapd); + if (hapd->beacon_set_done) + ieee802_11_set_beacon(hapd); return hostapd_set_ap_wps_ie(hapd); } @@ -184,11 +186,26 @@ static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, } +struct wps_stop_reg_data { + struct hostapd_data *current_hapd; + const u8 *uuid_e; +}; + +static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx) +{ + struct wps_stop_reg_data *data = ctx; + if (hapd != data->current_hapd && hapd->wps != NULL) + wps_registrar_complete(hapd->wps->registrar, data->uuid_e); + return 0; +} + + static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, const u8 *uuid_e) { struct hostapd_data *hapd = ctx; char uuid[40]; + struct wps_stop_reg_data data; if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) return; wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s", @@ -196,6 +213,9 @@ static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, if (hapd->wps_reg_success_cb) hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx, mac_addr, uuid_e); + data.current_hapd = hapd; + data.uuid_e = uuid_e; + hostapd_wps_for_each(hapd, wps_stop_registrar, &data); } @@ -240,6 +260,20 @@ static void wps_reload_config(void *eloop_data, void *user_ctx) } +static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr, + size_t attr_len) +{ + size_t blen = attr_len * 2 + 1; + char *buf = os_malloc(blen); + if (buf) { + wpa_snprintf_hex(buf, blen, attr, attr_len); + wpa_msg(hapd->msg_ctx, MSG_INFO, + WPS_EVENT_NEW_AP_SETTINGS "%s", buf); + os_free(buf); + } +} + + static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) { const struct wps_credential *cred = ctx; @@ -269,15 +303,15 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) if ((hapd->conf->wps_cred_processing == 1 || hapd->conf->wps_cred_processing == 2) && cred->cred_attr) { - size_t blen = cred->cred_attr_len * 2 + 1; - char *_buf = os_malloc(blen); - if (_buf) { - wpa_snprintf_hex(_buf, blen, - cred->cred_attr, cred->cred_attr_len); - wpa_msg(hapd->msg_ctx, MSG_INFO, "%s%s", - WPS_EVENT_NEW_AP_SETTINGS, _buf); - os_free(_buf); - } + hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len); + } else if (hapd->conf->wps_cred_processing == 1 || + hapd->conf->wps_cred_processing == 2) { + struct wpabuf *attr; + attr = wpabuf_alloc(200); + if (attr && wps_build_credential_wrap(attr, cred) == 0) + hapd_new_ap_event(hapd, wpabuf_head_u8(attr), + wpabuf_len(attr)); + wpabuf_free(attr); } else wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS); @@ -565,18 +599,22 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event, switch (event) { case WPS_EV_M2D: + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D); break; case WPS_EV_FAIL: hostapd_wps_event_fail(hapd, &data->fail); break; case WPS_EV_SUCCESS: + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS); break; case WPS_EV_PWD_AUTH_FAIL: hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail); break; case WPS_EV_PBC_OVERLAP: + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP); break; case WPS_EV_PBC_TIMEOUT: + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT); break; case WPS_EV_ER_AP_ADD: break; @@ -762,8 +800,14 @@ int hostapd_init_wps(struct hostapd_data *hapd, } wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version); - wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? - WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ + + if (conf->wps_rf_bands) { + wps->dev.rf_bands = conf->wps_rf_bands; + } else { + wps->dev.rf_bands = + hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? + WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ + } if (conf->wpa & WPA_PROTO_RSN) { if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) @@ -1076,7 +1120,8 @@ error: #endif /* CONFIG_WPS_OOB */ -static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, +static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da, + const u8 *bssid, const u8 *ie, size_t ie_len) { struct hostapd_data *hapd = ctx; @@ -1175,7 +1220,7 @@ static int hostapd_rx_req_put_wlan_response( } #endif /* CONFIG_WPS_STRICT */ - if (!sta) { + if (!sta || !(sta->flags & WLAN_STA_WPS)) { wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found"); return 0; } @@ -1240,6 +1285,7 @@ static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx) struct hostapd_data *hapd = eloop_data; wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out"); hostapd_wps_ap_pin_disable(hapd); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED); } @@ -1304,7 +1350,7 @@ const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout) struct wps_ap_pin_data data; pin = wps_generate_pin(); - os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%u", pin); + os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin); data.timeout = timeout; hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); return hapd->conf->ap_pin; diff --git a/src/common/defs.h b/src/common/defs.h index 8abec07..6082053 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -76,6 +76,11 @@ static inline int wpa_key_mgmt_wpa(int akm) wpa_key_mgmt_wpa_psk(akm); } +static inline int wpa_key_mgmt_wpa_any(int akm) +{ + return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE); +} + #define WPA_PROTO_WPA BIT(0) #define WPA_PROTO_RSN BIT(1) @@ -267,4 +272,21 @@ enum hostapd_hw_mode { NUM_HOSTAPD_MODES }; +/** + * enum wpa_ctrl_req_type - Control interface request types + */ +enum wpa_ctrl_req_type { + WPA_CTRL_REQ_UNKNOWN, + WPA_CTRL_REQ_EAP_IDENTITY, + WPA_CTRL_REQ_EAP_PASSWORD, + WPA_CTRL_REQ_EAP_NEW_PASSWORD, + WPA_CTRL_REQ_EAP_PIN, + WPA_CTRL_REQ_EAP_OTP, + WPA_CTRL_REQ_EAP_PASSPHRASE, + NUM_WPA_CTRL_REQS +}; + +/* Maximum number of EAP methods to store for EAP server user information */ +#define EAP_MAX_METHODS 8 + #endif /* DEFS_H */ diff --git a/src/common/gas.c b/src/common/gas.c new file mode 100644 index 0000000..babdaa3 --- /dev/null +++ b/src/common/gas.c @@ -0,0 +1,279 @@ +/* + * Generic advertisement service (GAS) (IEEE 802.11u) + * Copyright (c) 2009, Atheros Communications + * Copyright (c) 2011, Qualcomm Atheros + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "ieee802_11_defs.h" +#include "gas.h" + + +static struct wpabuf * +gas_build_req(u8 action, u8 dialog_token, size_t size) +{ + struct wpabuf *buf; + + buf = wpabuf_alloc(100 + size); + if (buf == NULL) + return NULL; + + wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); + wpabuf_put_u8(buf, action); + wpabuf_put_u8(buf, dialog_token); + + return buf; +} + + +static struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size) +{ + return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token, + size); +} + + +struct wpabuf * gas_build_comeback_req(u8 dialog_token) +{ + return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0); +} + + +static struct wpabuf * +gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id, + u8 more, u16 comeback_delay, size_t size) +{ + struct wpabuf *buf; + + buf = wpabuf_alloc(100 + size); + if (buf == NULL) + return NULL; + + wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); + wpabuf_put_u8(buf, action); + wpabuf_put_u8(buf, dialog_token); + wpabuf_put_le16(buf, status_code); + if (action == WLAN_PA_GAS_COMEBACK_RESP) + wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0)); + wpabuf_put_le16(buf, comeback_delay); + + return buf; +} + + +struct wpabuf * +gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay, + size_t size) +{ + return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token, + status_code, 0, 0, comeback_delay, size); +} + + +static struct wpabuf * +gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more, + u16 comeback_delay, size_t size) +{ + return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token, + status_code, frag_id, more, comeback_delay, + size); +} + + +/** + * gas_add_adv_proto_anqp - Add an Advertisement Protocol element + * @buf: Buffer to which the element is added + * @query_resp_len_limit: Query Response Length Limit in units of 256 octets + * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1) + * + * + * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means + * that the maximum limit is determined by the maximum allowable number of + * fragments in the GAS Query Response Fragment ID. + */ +static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit, + u8 pame_bi) +{ + /* Advertisement Protocol IE */ + wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); + wpabuf_put_u8(buf, 2); /* Length */ + wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) | + (pame_bi ? 0x80 : 0)); + /* Advertisement Protocol */ + wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL); +} + + +struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size) +{ + struct wpabuf *buf; + + buf = gas_build_initial_req(dialog_token, 4 + size); + if (buf == NULL) + return NULL; + + gas_add_adv_proto_anqp(buf, 0, 0); + + wpabuf_put(buf, 2); /* Query Request Length to be filled */ + + return buf; +} + + +struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code, + u16 comeback_delay, size_t size) +{ + struct wpabuf *buf; + + buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay, + 4 + size); + if (buf == NULL) + return NULL; + + gas_add_adv_proto_anqp(buf, 0x7f, 0); + + wpabuf_put(buf, 2); /* Query Response Length to be filled */ + + return buf; +} + + +struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token, + u16 status_code, + u16 comeback_delay, + struct wpabuf *payload) +{ + struct wpabuf *buf; + + buf = gas_anqp_build_initial_resp(dialog_token, status_code, + comeback_delay, + payload ? wpabuf_len(payload) : 0); + if (buf == NULL) + return NULL; + + if (payload) + wpabuf_put_buf(buf, payload); + + gas_anqp_set_len(buf); + + return buf; +} + + +struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code, + u8 frag_id, u8 more, + u16 comeback_delay, size_t size) +{ + struct wpabuf *buf; + + buf = gas_build_comeback_resp(dialog_token, status_code, + frag_id, more, comeback_delay, 4 + size); + if (buf == NULL) + return NULL; + + gas_add_adv_proto_anqp(buf, 0x7f, 0); + + wpabuf_put(buf, 2); /* Query Response Length to be filled */ + + return buf; +} + + +struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token, + u16 status_code, + u8 frag_id, u8 more, + u16 comeback_delay, + struct wpabuf *payload) +{ + struct wpabuf *buf; + + buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id, + more, comeback_delay, + payload ? wpabuf_len(payload) : 0); + if (buf == NULL) + return NULL; + + if (payload) + wpabuf_put_buf(buf, payload); + + gas_anqp_set_len(buf); + + return buf; +} + + +/** + * gas_anqp_set_len - Set Query Request/Response Length + * @buf: GAS message + * + * This function is used to update the Query Request/Response Length field once + * the payload has been filled. + */ +void gas_anqp_set_len(struct wpabuf *buf) +{ + u8 action; + size_t offset; + u8 *len; + + if (buf == NULL || wpabuf_len(buf) < 2) + return; + + action = *(wpabuf_head_u8(buf) + 1); + switch (action) { + case WLAN_PA_GAS_INITIAL_REQ: + offset = 3 + 4; + break; + case WLAN_PA_GAS_INITIAL_RESP: + offset = 7 + 4; + break; + case WLAN_PA_GAS_COMEBACK_RESP: + offset = 8 + 4; + break; + default: + return; + } + + if (wpabuf_len(buf) < offset + 2) + return; + + len = wpabuf_mhead_u8(buf) + offset; + WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); +} + + +/** + * gas_anqp_add_element - Add ANQP element header + * @buf: GAS message + * @info_id: ANQP Info ID + * Returns: Pointer to the Length field for gas_anqp_set_element_len() + */ +u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id) +{ + wpabuf_put_le16(buf, info_id); + return wpabuf_put(buf, 2); /* Length to be filled */ +} + + +/** + * gas_anqp_set_element_len - Update ANQP element Length field + * @buf: GAS message + * @len_pos: Length field position from gas_anqp_add_element() + * + * This function is called after the ANQP element payload has been added to the + * buffer. + */ +void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos) +{ + WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2); +} diff --git a/src/common/gas.h b/src/common/gas.h new file mode 100644 index 0000000..2f8d2cb --- /dev/null +++ b/src/common/gas.h @@ -0,0 +1,42 @@ +/* + * Generic advertisement service (GAS) (IEEE 802.11u) + * Copyright (c) 2009, Atheros Communications + * Copyright (c) 2011, Qualcomm Atheros + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef GAS_H +#define GAS_H + +struct wpabuf * gas_build_comeback_req(u8 dialog_token); +struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code, + u16 comeback_delay, size_t size); +struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size); +struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code, + u16 comeback_delay, size_t size); +struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token, + u16 status_code, + u16 comeback_delay, + struct wpabuf *payload); +struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code, + u8 frag_id, u8 more, + u16 comeback_delay, size_t size); +struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token, + u16 status_code, + u8 frag_id, u8 more, + u16 comeback_delay, + struct wpabuf *payload); +void gas_anqp_set_len(struct wpabuf *buf); + +u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id); +void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos); + +#endif /* GAS_H */ diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index ee41b3a..43cb2c6 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -259,6 +259,10 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, break; elems->link_id = pos; break; + case WLAN_EID_INTERWORKING: + elems->interworking = pos; + elems->interworking_len = elen; + break; default: unknown++; if (!show_errors) @@ -345,3 +349,43 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, return buf; } + + +const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) +{ + u16 fc, type, stype; + + /* + * PS-Poll frames are 16 bytes. All other frames are + * 24 bytes or longer. + */ + if (len < 16) + return NULL; + + fc = le_to_host16(hdr->frame_control); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + + switch (type) { + case WLAN_FC_TYPE_DATA: + if (len < 24) + return NULL; + switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { + case WLAN_FC_FROMDS | WLAN_FC_TODS: + case WLAN_FC_TODS: + return hdr->addr1; + case WLAN_FC_FROMDS: + return hdr->addr2; + default: + return NULL; + } + case WLAN_FC_TYPE_CTRL: + if (stype != WLAN_FC_STYPE_PSPOLL) + return NULL; + return hdr->addr1; + case WLAN_FC_TYPE_MGMT: + return hdr->addr3; + default: + return NULL; + } +} diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 0c90fa4..60f0974 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -42,6 +42,7 @@ struct ieee802_11_elems { const u8 *vendor_ht_cap; const u8 *p2p; const u8 *link_id; + const u8 *interworking; u8 ssid_len; u8 supp_rates_len; @@ -67,6 +68,7 @@ struct ieee802_11_elems { u8 ht_operation_len; u8 vendor_ht_cap_len; u8 p2p_len; + u8 interworking_len; }; typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; @@ -77,5 +79,7 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, int ieee802_11_ie_count(const u8 *ies, size_t ies_len); struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, u32 oui_type); +struct ieee80211_hdr; +const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len); #endif /* IEEE802_11_COMMON_H */ diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 86868c0..66801fd 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -153,7 +153,17 @@ #define WLAN_STATUS_INVALID_PMKID 53 #define WLAN_STATUS_INVALID_MDIE 54 #define WLAN_STATUS_INVALID_FTIE 55 +#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59 +#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60 +#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61 +#define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62 +#define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63 +#define WLAN_STATUS_REQ_REFUSED_HOME 64 +#define WLAN_STATUS_ADV_SRV_UNREACHABLE 65 +#define WLAN_STATUS_REQ_REFUSED_SSPN 67 +#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68 #define WLAN_STATUS_INVALID_RSNIE 72 +#define WLAN_STATUS_TRANSMISSION_FAILURE 79 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ #define WLAN_REASON_UNSPECIFIED 1 @@ -219,12 +229,16 @@ #define WLAN_EID_RIC_DATA 57 #define WLAN_EID_HT_OPERATION 61 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 +#define WLAN_EID_TIME_ADVERTISEMENT 69 #define WLAN_EID_20_40_BSS_COEXISTENCE 72 #define WLAN_EID_20_40_BSS_INTOLERANT 73 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 #define WLAN_EID_MMIE 76 +#define WLAN_EID_TIME_ZONE 98 #define WLAN_EID_LINK_ID 101 +#define WLAN_EID_INTERWORKING 107 #define WLAN_EID_ADV_PROTO 108 +#define WLAN_EID_ROAMING_CONSORTIUM 111 #define WLAN_EID_EXT_CAPAB 127 #define WLAN_EID_VENDOR_SPECIFIC 221 @@ -239,6 +253,8 @@ #define WLAN_ACTION_FT 6 #define WLAN_ACTION_HT 7 #define WLAN_ACTION_SA_QUERY 8 +#define WLAN_ACTION_WNM 10 +#define WLAN_ACTION_UNPROTECTED_WNM 11 #define WLAN_ACTION_TDLS 12 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */ #define WLAN_ACTION_VENDOR_SPECIFIC 127 @@ -249,6 +265,7 @@ #define WLAN_PA_GAS_INITIAL_RESP 11 #define WLAN_PA_GAS_COMEBACK_REQ 12 #define WLAN_PA_GAS_COMEBACK_RESP 13 +#define WLAN_TDLS_DISCOVERY_RESPONSE 14 /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ #define WLAN_SA_QUERY_REQUEST 0 @@ -274,33 +291,81 @@ #define WLAN_TIMEOUT_KEY_LIFETIME 2 #define WLAN_TIMEOUT_ASSOC_COMEBACK 3 -/* Advertisement Protocol ID definitions (IEEE 802.11u) */ +/* Interworking element (IEEE 802.11u) - Access Network Options */ +#define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f +#define INTERWORKING_ANO_INTERNET 0x10 +#define INTERWORKING_ANO_ASRA 0x20 +#define INTERWORKING_ANO_ESR 0x40 +#define INTERWORKING_ANO_UESA 0x80 + +#define INTERWORKING_ANT_PRIVATE 0 +#define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1 +#define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2 +#define INTERWORKING_ANT_FREE_PUBLIC 3 +#define INTERWORKING_ANT_PERSONAL_DEVICE 4 +#define INTERWORKING_ANT_EMERGENCY_SERVICES 5 +#define INTERWORKING_ANT_TEST 6 +#define INTERWORKING_ANT_WILDCARD 15 + +/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */ enum adv_proto_id { - NATIVE_QUERY_PROTOCOL = 0, + ACCESS_NETWORK_QUERY_PROTOCOL = 0, MIH_INFO_SERVICE = 1, MIH_CMD_AND_EVENT_DISCOVERY = 2, EMERGENCY_ALERT_SYSTEM = 3, - LOCATION_TO_SERVICE = 4, ADV_PROTO_VENDOR_SPECIFIC = 221 }; -/* Native Query Protocol info ID definitions (IEEE 802.11u) */ -enum nqp_info_id { - NQP_CAPABILITY_LIST = 256, - NQP_VENUE_NAME = 257, - NQP_EMERGENCY_CALL_NUMBER = 258, - NQP_NETWORK_AUTH_TYPE = 259, - NQP_ROAMING_CONSORTIUM = 260, - NQP_IP_ADDR_TYPE_AVAILABILITY = 261, - NQP_NAI_REALM = 262, - NQP_3GPP_CELLULAR_NETWORK = 263, - NQP_AP_GEOSPATIAL_LOCATION = 264, - NQP_AP_CIVIC_LOCATION = 265, - NQP_DOMAIN_NAME = 266, - NQP_EMERGENCY_ALERT_URI = 267, - NQP_VENDOR_SPECIFIC = 56797 +/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */ +enum anqp_info_id { + ANQP_QUERY_LIST = 256, + ANQP_CAPABILITY_LIST = 257, + ANQP_VENUE_NAME = 258, + ANQP_EMERGENCY_CALL_NUMBER = 259, + ANQP_NETWORK_AUTH_TYPE = 260, + ANQP_ROAMING_CONSORTIUM = 261, + ANQP_IP_ADDR_TYPE_AVAILABILITY = 262, + ANQP_NAI_REALM = 263, + ANQP_3GPP_CELLULAR_NETWORK = 264, + ANQP_AP_GEOSPATIAL_LOCATION = 265, + ANQP_AP_CIVIC_LOCATION = 266, + ANQP_AP_LOCATION_PUBLIC_URI = 267, + ANQP_DOMAIN_NAME = 268, + ANQP_EMERGENCY_ALERT_URI = 269, + ANQP_EMERGENCY_NAI = 271, + ANQP_VENDOR_SPECIFIC = 56797 }; +/* NAI Realm list - EAP Method subfield - Authentication Parameter ID */ +enum nai_realm_eap_auth_param { + NAI_REALM_EAP_AUTH_EXPANDED_EAP_METHOD = 1, + NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH = 2, + NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD = 3, + NAI_REALM_EAP_AUTH_EXPANDED_INNER_EAP_METHOD = 4, + NAI_REALM_EAP_AUTH_CRED_TYPE = 5, + NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE = 6, + NAI_REALM_EAP_AUTH_VENDOR_SPECIFIC = 221 +}; + +enum nai_realm_eap_auth_inner_non_eap { + NAI_REALM_INNER_NON_EAP_PAP = 1, + NAI_REALM_INNER_NON_EAP_CHAP = 2, + NAI_REALM_INNER_NON_EAP_MSCHAP = 3, + NAI_REALM_INNER_NON_EAP_MSCHAPV2 = 4 +}; + +enum nai_realm_eap_cred_type { + NAI_REALM_CRED_TYPE_SIM = 1, + NAI_REALM_CRED_TYPE_USIM = 2, + NAI_REALM_CRED_TYPE_NFC_SECURE_ELEMENT = 3, + NAI_REALM_CRED_TYPE_HARDWARE_TOKEN = 4, + NAI_REALM_CRED_TYPE_SOFTOKEN = 5, + NAI_REALM_CRED_TYPE_CERTIFICATE = 6, + NAI_REALM_CRED_TYPE_USERNAME_PASSWORD = 7, + NAI_REALM_CRED_TYPE_NONE = 8, + NAI_REALM_CRED_TYPE_ANONYMOUS = 9, + NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10 +}; #ifdef _MSC_VER #pragma pack(push, 1) @@ -436,6 +501,18 @@ struct ieee80211_mgmt { /* Vendor-specific content */ u8 variable[0]; } STRUCT_PACKED vs_public_action; + struct { + u8 action; /* 7 */ + u8 dialog_token; + u8 req_mode; + le16 disassoc_timer; + u8 validity_interval; + /* BSS Termination Duration (optional), + * Session Information URL (optional), + * BSS Transition Candidate List + * Entries */ + u8 variable[0]; + } STRUCT_PACKED bss_tm_req; } u; } STRUCT_PACKED action; } u; @@ -541,7 +618,7 @@ struct ieee80211_ht_operation { #define OP_MODE_MIXED 3 #define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ - ((le16) (0x0001 | 0x0002)) + (0x0001 | 0x0002) #define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 #define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2)) #define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3)) @@ -600,6 +677,10 @@ struct wmm_information_element { } STRUCT_PACKED; +#define WMM_QOSINFO_STA_AC_MASK 0x0f +#define WMM_QOSINFO_STA_SP_MASK 0x03 +#define WMM_QOSINFO_STA_SP_SHIFT 5 + #define WMM_AC_AIFSN_MASK 0x0f #define WMM_AC_AIFNS_SHIFT 0 #define WMM_AC_ACM 0x10 @@ -628,7 +709,7 @@ struct wmm_parameter_element { u8 oui_type; /* 2 */ u8 oui_subtype; /* 1 */ u8 version; /* 1 for WMM version 1.0 */ - u8 qos_info; /* AP/STA specif QoS info */ + u8 qos_info; /* AP/STA specific QoS info */ u8 reserved; /* 0 */ struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */ @@ -797,4 +878,44 @@ enum p2p_sd_status { #define WLAN_AKM_SUITE_8021X 0x000FAC01 #define WLAN_AKM_SUITE_PSK 0x000FAC02 + +/* IEEE 802.11v - WNM Action field values */ +enum wnm_action { + WNM_EVENT_REQ = 0, + WNM_EVENT_REPORT = 1, + WNM_DIAGNOSTIC_REQ = 2, + WNM_DIAGNOSTIC_REPORT = 3, + WNM_LOCATION_CFG_REQ = 4, + WNM_LOCATION_CFG_RESP = 5, + WNM_BSS_TRANS_MGMT_QUERY = 6, + WNM_BSS_TRANS_MGMT_REQ = 7, + WNM_BSS_TRANS_MGMT_RESP = 8, + WNM_FMS_REQ = 9, + WNM_FMS_RESP = 10, + WNM_COLLOCATED_INTERFERENCE_REQ = 11, + WNM_COLLOCATED_INTERFERENCE_REPORT = 12, + WNM_TFS_REQ = 13, + WNM_TFS_RESP = 14, + WNM_TFS_NOTIFY = 15, + WNM_SLEEP_MODE_REQ = 16, + WNM_SLEEP_MODE_RESP = 17, + WNM_TIM_BROADCAST_REQ = 18, + WNM_TIM_BROADCAST_RESP = 19, + WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20, + WNM_CHANNEL_USAGE_REQ = 21, + WNM_CHANNEL_USAGE_RESP = 22, + WNM_DMS_REQ = 23, + WNM_DMS_RESP = 24, + WNM_TIMING_MEASUREMENT_REQ = 25, + WNM_NOTIFICATION_REQ = 26, + WNM_NOTIFICATION_RESP = 27 +}; + +/* IEEE 802.11v - BSS Transition Management Request - Request Mode */ +#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0) +#define WNM_BSS_TM_REQ_ABRIDGED BIT(1) +#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2) +#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3) +#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4) + #endif /* IEEE802_11_DEFS_H */ diff --git a/src/common/version.h b/src/common/version.h index ba2d2c0..7afba48 100644 --- a/src/common/version.h +++ b/src/common/version.h @@ -5,6 +5,6 @@ #define VERSION_STR_POSTFIX "" #endif /* VERSION_STR_POSTFIX */ -#define VERSION_STR "0.8.x" VERSION_STR_POSTFIX +#define VERSION_STR "2.0-devel" VERSION_STR_POSTFIX #endif /* VERSION_H */ diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index eb2745e..24a61e4 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -188,6 +188,154 @@ int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, return 0; } + + +static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, + struct wpa_ft_ies *parse) +{ + const u8 *end, *pos; + + parse->ftie = ie; + parse->ftie_len = ie_len; + + pos = ie + sizeof(struct rsn_ftie); + end = ie + ie_len; + + while (pos + 2 <= end && pos + 2 + pos[1] <= end) { + switch (pos[0]) { + 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]); + return -1; + } + parse->r1kh_id = pos + 2; + break; + case FTIE_SUBELEM_GTK: + parse->gtk = pos + 2; + parse->gtk_len = pos[1]; + 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]); + return -1; + } + parse->r0kh_id = pos + 2; + parse->r0kh_id_len = pos[1]; + break; +#ifdef CONFIG_IEEE80211W + case FTIE_SUBELEM_IGTK: + parse->igtk = pos + 2; + parse->igtk_len = pos[1]; + break; +#endif /* CONFIG_IEEE80211W */ + } + + pos += 2 + pos[1]; + } + + return 0; +} + + +int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, + struct wpa_ft_ies *parse) +{ + const u8 *end, *pos; + struct wpa_ie_data data; + int ret; + const struct rsn_ftie *ftie; + int prot_ie_count = 0; + + os_memset(parse, 0, sizeof(*parse)); + if (ies == NULL) + return 0; + + pos = ies; + end = ies + ies_len; + while (pos + 2 <= end && pos + 2 + pos[1] <= end) { + switch (pos[0]) { + case WLAN_EID_RSN: + parse->rsn = pos + 2; + parse->rsn_len = pos[1]; + ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, + parse->rsn_len + 2, + &data); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "FT: Failed to parse " + "RSN IE: %d", ret); + return -1; + } + if (data.num_pmkid == 1 && data.pmkid) + parse->rsn_pmkid = data.pmkid; + break; + case WLAN_EID_MOBILITY_DOMAIN: + parse->mdie = pos + 2; + parse->mdie_len = pos[1]; + break; + case WLAN_EID_FAST_BSS_TRANSITION: + if (pos[1] < sizeof(*ftie)) + return -1; + ftie = (const struct rsn_ftie *) (pos + 2); + prot_ie_count = ftie->mic_control[1]; + if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) + return -1; + break; + case WLAN_EID_TIMEOUT_INTERVAL: + parse->tie = pos + 2; + parse->tie_len = pos[1]; + break; + case WLAN_EID_RIC_DATA: + if (parse->ric == NULL) + parse->ric = pos; + break; + } + + pos += 2 + pos[1]; + } + + if (prot_ie_count == 0) + return 0; /* no MIC */ + + /* + * Check that the protected IE count matches with IEs included in the + * frame. + */ + if (parse->rsn) + prot_ie_count--; + if (parse->mdie) + prot_ie_count--; + if (parse->ftie) + prot_ie_count--; + if (prot_ie_count < 0) { + wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " + "the protected IE count"); + return -1; + } + + if (prot_ie_count == 0 && parse->ric) { + wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " + "included in protected IE count"); + return -1; + } + + /* 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]; + } + 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); + return -1; + } + + return 0; +} #endif /* CONFIG_IEEE80211R */ diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index fe79cee..69437a7 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -358,4 +358,27 @@ int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie2, size_t ie2len); int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid); +struct wpa_ft_ies { + const u8 *mdie; + size_t mdie_len; + const u8 *ftie; + size_t ftie_len; + const u8 *r1kh_id; + const u8 *gtk; + size_t gtk_len; + const u8 *r0kh_id; + size_t r0kh_id_len; + const u8 *rsn; + size_t rsn_len; + const u8 *rsn_pmkid; + const u8 *tie; + size_t tie_len; + const u8 *igtk; + size_t igtk_len; + const u8 *ric; + size_t ric_len; +}; + +int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse); + #endif /* WPA_COMMON_H */ diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index 88d3a02..3b25f77 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -21,6 +21,7 @@ #endif /* CONFIG_CTRL_IFACE_UNIX */ #ifdef ANDROID +#include <dirent.h> #include <cutils/sockets.h> #include "private/android_filesystem_config.h" #endif /* ANDROID */ @@ -175,6 +176,56 @@ void wpa_ctrl_close(struct wpa_ctrl *ctrl) os_free(ctrl); } + +#ifdef ANDROID +/** + * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that + * may be left over from clients that were previously connected to + * wpa_supplicant. This keeps these files from being orphaned in the + * event of crashes that prevented them from being removed as part + * of the normal orderly shutdown. + */ +void wpa_ctrl_cleanup(void) +{ + DIR *dir; + struct dirent entry; + struct dirent *result; + size_t dirnamelen; + int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX); + size_t maxcopy; + char pathname[PATH_MAX]; + char *namep; + + if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL) + return; + + dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/", + CONFIG_CTRL_IFACE_CLIENT_DIR); + if (dirnamelen >= sizeof(pathname)) { + closedir(dir); + return; + } + namep = pathname + dirnamelen; + maxcopy = PATH_MAX - dirnamelen; + while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { + if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX, + prefixlen) == 0) { + if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy) + unlink(pathname); + } + } + closedir(dir); +} +#endif /* ANDROID */ + +#else /* CONFIG_CTRL_IFACE_UNIX */ + +#ifdef ANDROID +void wpa_ctrl_cleanup(void) +{ +} +#endif /* ANDROID */ + #endif /* CONFIG_CTRL_IFACE_UNIX */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 35e5e3d..d13ba02 100644..100755 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -100,10 +100,8 @@ extern "C" { /** P2P device found */ #define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND " -#ifdef ANDROID_BRCM_P2P_PATCH /** P2P device lost */ #define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST " -#endif /** A P2P device requested GO negotiation, but we were not ready to start the * negotiation */ @@ -130,6 +128,10 @@ extern "C" { #define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP " #define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED " #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT " +#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED " + +#define INTERWORKING_AP "INTERWORKING-AP " +#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH " /* hostapd control interface - fixed message prefixes */ #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED " @@ -267,6 +269,17 @@ int wpa_ctrl_pending(struct wpa_ctrl *ctrl); */ int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl); +#ifdef ANDROID +/** + * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that + * may be left over from clients that were previously connected to + * wpa_supplicant. This keeps these files from being orphaned in the + * event of crashes that prevented them from being removed as part + * of the normal orderly shutdown. + */ +void wpa_ctrl_cleanup(void); +#endif /* ANDROID */ + #ifdef CONFIG_CTRL_IFACE_UDP #define WPA_CTRL_IFACE_PORT 9877 #define WPA_GLOBAL_CTRL_IFACE_PORT 9878 diff --git a/src/crypto/Makefile b/src/crypto/Makefile index 69aa16a..b221dd4 100644 --- a/src/crypto/Makefile +++ b/src/crypto/Makefile @@ -12,6 +12,7 @@ include ../lib.rules CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER #CFLAGS += -DALL_DH_GROUPS +CFLAGS += -DCONFIG_SHA256 LIB_OBJS= \ aes-cbc.o \ @@ -40,6 +41,7 @@ LIB_OBJS= \ sha1-tlsprf.o \ sha1-tprf.o \ sha256.o \ + sha256-tlsprf.o \ sha256-internal.o LIB_OBJS += crypto_internal.o @@ -48,6 +50,7 @@ LIB_OBJS += crypto_internal-modexp.o LIB_OBJS += crypto_internal-rsa.o LIB_OBJS += tls_internal.o LIB_OBJS += fips_prf_internal.o +LIB_OBJS += random.o libcrypto.a: $(LIB_OBJS) diff --git a/src/crypto/aes-internal-dec.c b/src/crypto/aes-internal-dec.c index 2d32c03..a0fc45b 100644 --- a/src/crypto/aes-internal-dec.c +++ b/src/crypto/aes-internal-dec.c @@ -32,7 +32,7 @@ * * @return the number of rounds for the given cipher key size. */ -void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[]) +static void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[]) { int Nr = 10, i, j; u32 temp; diff --git a/src/crypto/aes-internal-enc.c b/src/crypto/aes-internal-enc.c index 2f19826..8726aa7 100644 --- a/src/crypto/aes-internal-enc.c +++ b/src/crypto/aes-internal-enc.c @@ -27,7 +27,7 @@ #include "crypto.h" #include "aes_i.h" -void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16]) +static void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; const int Nr = 10; diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 587b5a9..6dca191 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -155,7 +155,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_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1, + CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256 }; struct crypto_hash; diff --git a/src/crypto/crypto_internal-rsa.c b/src/crypto/crypto_internal-rsa.c index 205042c..7f0a5cf 100644 --- a/src/crypto/crypto_internal-rsa.c +++ b/src/crypto/crypto_internal-rsa.c @@ -17,7 +17,6 @@ #include "common.h" #include "crypto.h" #include "tls/rsa.h" -#include "tls/bignum.h" #include "tls/pkcs1.h" #include "tls/pkcs8.h" diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c index 8fdba65..9362fe1 100644 --- a/src/crypto/crypto_internal.c +++ b/src/crypto/crypto_internal.c @@ -1,6 +1,6 @@ /* * Crypto wrapper for internal crypto implementation - * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,6 +16,7 @@ #include "common.h" #include "crypto.h" +#include "sha256_i.h" #include "sha1_i.h" #include "md5_i.h" @@ -24,6 +25,9 @@ struct crypto_hash { union { struct MD5Context md5; struct SHA1Context sha1; +#ifdef CONFIG_SHA256 + struct sha256_state sha256; +#endif /* CONFIG_SHA256 */ } u; u8 key[64]; size_t key_len; @@ -35,7 +39,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, { struct crypto_hash *ctx; u8 k_pad[64]; - u8 tk[20]; + u8 tk[32]; size_t i; ctx = os_zalloc(sizeof(*ctx)); @@ -51,6 +55,11 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, case CRYPTO_HASH_ALG_SHA1: SHA1Init(&ctx->u.sha1); break; +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_SHA256: + sha256_init(&ctx->u.sha256); + break; +#endif /* CONFIG_SHA256 */ case CRYPTO_HASH_ALG_HMAC_MD5: if (key_len > sizeof(k_pad)) { MD5Init(&ctx->u.md5); @@ -63,7 +72,8 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, ctx->key_len = key_len; os_memcpy(k_pad, key, key_len); - os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); + if (key_len < sizeof(k_pad)) + os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); for (i = 0; i < sizeof(k_pad); i++) k_pad[i] ^= 0x36; MD5Init(&ctx->u.md5); @@ -81,12 +91,34 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, ctx->key_len = key_len; os_memcpy(k_pad, key, key_len); - os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); + if (key_len < sizeof(k_pad)) + os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); for (i = 0; i < sizeof(k_pad); i++) k_pad[i] ^= 0x36; SHA1Init(&ctx->u.sha1); SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); break; +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_HMAC_SHA256: + if (key_len > sizeof(k_pad)) { + sha256_init(&ctx->u.sha256); + sha256_process(&ctx->u.sha256, key, key_len); + sha256_done(&ctx->u.sha256, tk); + key = tk; + key_len = 32; + } + os_memcpy(ctx->key, key, key_len); + ctx->key_len = key_len; + + os_memcpy(k_pad, key, key_len); + if (key_len < sizeof(k_pad)) + os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x36; + sha256_init(&ctx->u.sha256); + sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad)); + break; +#endif /* CONFIG_SHA256 */ default: os_free(ctx); return NULL; @@ -110,6 +142,14 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) case CRYPTO_HASH_ALG_HMAC_SHA1: SHA1Update(&ctx->u.sha1, data, len); break; +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_SHA256: + case CRYPTO_HASH_ALG_HMAC_SHA256: + sha256_process(&ctx->u.sha256, data, len); + break; +#endif /* CONFIG_SHA256 */ + default: + break; } } @@ -146,6 +186,17 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) *len = 20; SHA1Final(mac, &ctx->u.sha1); break; +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_SHA256: + if (*len < 32) { + *len = 32; + os_free(ctx); + return -1; + } + *len = 32; + sha256_done(&ctx->u.sha256, mac); + break; +#endif /* CONFIG_SHA256 */ case CRYPTO_HASH_ALG_HMAC_MD5: if (*len < 16) { *len = 16; @@ -186,6 +237,31 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) SHA1Update(&ctx->u.sha1, mac, 20); SHA1Final(mac, &ctx->u.sha1); break; +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_HMAC_SHA256: + if (*len < 32) { + *len = 32; + os_free(ctx); + return -1; + } + *len = 32; + + sha256_done(&ctx->u.sha256, mac); + + os_memcpy(k_pad, ctx->key, ctx->key_len); + os_memset(k_pad + ctx->key_len, 0, + sizeof(k_pad) - ctx->key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x5c; + sha256_init(&ctx->u.sha256); + sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad)); + sha256_process(&ctx->u.sha256, mac, 32); + sha256_done(&ctx->u.sha256, mac); + break; +#endif /* CONFIG_SHA256 */ + default: + os_free(ctx); + return -1; } os_free(ctx); diff --git a/src/crypto/dh_group5.c b/src/crypto/dh_group5.c index 8c475bf..2a67d99 100644 --- a/src/crypto/dh_group5.c +++ b/src/crypto/dh_group5.c @@ -22,7 +22,7 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) { *publ = dh_init(dh_groups_get(5), priv); - if (*publ == 0) + if (*publ == NULL) return NULL; return (void *) 1; } diff --git a/src/crypto/fips_prf_internal.c b/src/crypto/fips_prf_internal.c index a85cb14..1e0c453 100644 --- a/src/crypto/fips_prf_internal.c +++ b/src/crypto/fips_prf_internal.c @@ -28,13 +28,14 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) u8 *xpos = x; u32 carry; - if (seed_len > sizeof(xkey)) + if (seed_len < sizeof(xkey)) + os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len); + else seed_len = sizeof(xkey); /* FIPS 186-2 + change notice 1 */ os_memcpy(xkey, seed, seed_len); - os_memset(xkey + seed_len, 0, 64 - seed_len); t[0] = 0x67452301; t[1] = 0xEFCDAB89; t[2] = 0x98BADCFE; diff --git a/src/crypto/md5-internal.c b/src/crypto/md5-internal.c index f8692a9..137ad91 100644 --- a/src/crypto/md5-internal.c +++ b/src/crypto/md5-internal.c @@ -188,7 +188,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx) MD5Transform(ctx->buf, (u32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); os_memcpy(digest, ctx->buf, 16); - os_memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ + os_memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c index dae15ab..c439ae9 100644 --- a/src/crypto/ms_funcs.c +++ b/src/crypto/ms_funcs.c @@ -19,6 +19,60 @@ #include "ms_funcs.h" #include "crypto.h" +/** + * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding + * @utf8_string: UTF-8 string (IN) + * @utf8_string_len: Length of utf8_string (IN) + * @ucs2_buffer: UCS-2 buffer (OUT) + * @ucs2_buffer_size: Length of UCS-2 buffer (IN) + * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string + * Returns: 0 on success, -1 on failure + */ +static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len, + u8 *ucs2_buffer, size_t ucs2_buffer_size, + size_t *ucs2_string_size) +{ + size_t i, j; + + for (i = 0, j = 0; i < utf8_string_len; i++) { + u8 c = utf8_string[i]; + if (j >= ucs2_buffer_size) { + /* input too long */ + return -1; + } + if (c <= 0x7F) { + WPA_PUT_LE16(ucs2_buffer + j, c); + j += 2; + } else if (i == utf8_string_len - 1 || + j >= ucs2_buffer_size - 1) { + /* incomplete surrogate */ + return -1; + } else { + u8 c2 = utf8_string[++i]; + if ((c & 0xE0) == 0xC0) { + /* two-byte encoding */ + WPA_PUT_LE16(ucs2_buffer + j, + ((c & 0x1F) << 6) | (c2 & 0x3F)); + j += 2; + } else if (i == utf8_string_len || + j >= ucs2_buffer_size - 1) { + /* incomplete surrogate */ + return -1; + } else { + /* three-byte encoding */ + u8 c3 = utf8_string[++i]; + WPA_PUT_LE16(ucs2_buffer + j, + ((c & 0xF) << 12) | + ((c2 & 0x3F) << 6) | (c3 & 0x3F)); + } + } + } + + if (ucs2_string_size) + *ucs2_string_size = j / 2; + return 0; +} + /** * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2 @@ -53,7 +107,7 @@ static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, /** * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3 - * @password: 0-to-256-unicode-char Password (IN; ASCII) + * @password: 0-to-256-unicode-char Password (IN; UTF-8) * @password_len: Length of password * @password_hash: 16-octet PasswordHash (OUT) * Returns: 0 on success, -1 on failure @@ -62,18 +116,13 @@ int nt_password_hash(const u8 *password, size_t password_len, u8 *password_hash) { u8 buf[512], *pos; - size_t i, len; + size_t len, max_len; - if (password_len > 256) - password_len = 256; - - /* Convert password into unicode */ - for (i = 0; i < password_len; i++) { - buf[2 * i] = password[i]; - buf[2 * i + 1] = 0; - } + max_len = sizeof(buf); + if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0) + return -1; - len = password_len * 2; + len *= 2; pos = buf; return md4_vector(1, (const u8 **) &pos, &len, password_hash); } @@ -117,7 +166,7 @@ void challenge_response(const u8 *challenge, const u8 *password_hash, * @peer_challenge: 16-octet PeerChallenge (IN) * @username: 0-to-256-char UserName (IN) * @username_len: Length of username - * @password: 0-to-256-unicode-char Password (IN; ASCII) + * @password: 0-to-256-unicode-char Password (IN; UTF-8) * @password_len: Length of password * @response: 24-octet Response (OUT) * Returns: 0 on success, -1 on failure @@ -225,7 +274,7 @@ int generate_authenticator_response_pwhash( /** * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 - * @password: 0-to-256-unicode-char Password (IN; ASCII) + * @password: 0-to-256-unicode-char Password (IN; UTF-8) * @password_len: Length of password * @nt_response: 24-octet NT-Response (IN) * @peer_challenge: 16-octet PeerChallenge (IN) @@ -254,7 +303,7 @@ int generate_authenticator_response(const u8 *password, size_t password_len, /** * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5 * @challenge: 8-octet Challenge (IN) - * @password: 0-to-256-unicode-char Password (IN; ASCII) + * @password: 0-to-256-unicode-char Password (IN; UTF-8) * @password_len: Length of password * @response: 24-octet Response (OUT) * Returns: 0 on success, -1 on failure @@ -375,7 +424,7 @@ int get_asymetric_start_key(const u8 *master_key, u8 *session_key, /** * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10 - * @password: 0-to-256-unicode-char Password (IN; ASCII) + * @password: 0-to-256-unicode-char Password (IN; UTF-8) * @password_len: Length of password * @password_hash: 16-octet PasswordHash (IN) * @pw_block: 516-byte PwBlock (OUT) @@ -385,18 +434,23 @@ int encrypt_pw_block_with_password_hash( const u8 *password, size_t password_len, const u8 *password_hash, u8 *pw_block) { - size_t i, offset; + size_t ucs2_len, offset; u8 *pos; - if (password_len > 256) + os_memset(pw_block, 0, PWBLOCK_LEN); + + if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0) return -1; - os_memset(pw_block, 0, PWBLOCK_LEN); - offset = (256 - password_len) * 2; - if (os_get_random(pw_block, offset) < 0) + if (ucs2_len > 256) return -1; - for (i = 0; i < password_len; i++) - pw_block[offset + i * 2] = password[i]; + + offset = (256 - ucs2_len) * 2; + if (offset != 0) { + os_memmove(pw_block + offset, pw_block, ucs2_len * 2); + if (os_get_random(pw_block, offset) < 0) + return -1; + } /* * PasswordLength is 4 octets, but since the maximum password length is * 256, only first two (in little endian byte order) can be non-zero. @@ -410,9 +464,9 @@ int encrypt_pw_block_with_password_hash( /** * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9 - * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII) + * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8) * @new_password_len: Length of new_password - * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) + * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8) * @old_password_len: Length of old_password * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT) * Returns: 0 on success, -1 on failure @@ -450,9 +504,9 @@ void nt_password_hash_encrypted_with_block(const u8 *password_hash, /** * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12 - * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII) + * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8) * @new_password_len: Length of new_password - * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) + * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8) * @old_password_len: Length of old_password * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT) * Returns: 0 on success, -1 on failure diff --git a/src/crypto/random.c b/src/crypto/random.c index f545917..a54e197 100644 --- a/src/crypto/random.c +++ b/src/crypto/random.c @@ -354,23 +354,31 @@ static void random_write_entropy(void) char buf[RANDOM_ENTROPY_SIZE]; FILE *f; u8 opr; + int fail = 0; if (!random_entropy_file) return; - random_get_bytes(buf, RANDOM_ENTROPY_SIZE); + if (random_get_bytes(buf, RANDOM_ENTROPY_SIZE) < 0) + return; f = fopen(random_entropy_file, "wb"); if (f == NULL) { - wpa_printf(MSG_ERROR, "random: Could not write %s", - random_entropy_file); + wpa_printf(MSG_ERROR, "random: Could not open entropy file %s " + "for writing", random_entropy_file); return; } opr = own_pool_ready > 0xff ? 0xff : own_pool_ready; - fwrite(&opr, 1, 1, f); - fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f); + if (fwrite(&opr, 1, 1, f) != 1 || + fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f) != 1) + fail = 1; fclose(f); + if (fail) { + wpa_printf(MSG_ERROR, "random: Could not write entropy data " + "to %s", random_entropy_file); + return; + } wpa_printf(MSG_DEBUG, "random: Updated entropy file %s " "(own_pool_ready=%u)", diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c index 11323de..9dac977 100644 --- a/src/crypto/sha1-pbkdf2.c +++ b/src/crypto/sha1-pbkdf2.c @@ -16,8 +16,6 @@ #include "common.h" #include "sha1.h" -#include "md5.h" -#include "crypto.h" static int pbkdf2_sha1_f(const char *passphrase, const char *ssid, size_t ssid_len, int iterations, unsigned int count, diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c index 2c8c029..f98fd65 100644 --- a/src/crypto/sha1-tlsprf.c +++ b/src/crypto/sha1-tlsprf.c @@ -17,11 +17,10 @@ #include "common.h" #include "sha1.h" #include "md5.h" -#include "crypto.h" /** - * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246) + * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246) * @secret: Key for PRF * @secret_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF @@ -34,8 +33,8 @@ * This function is used to derive new, cryptographically separate keys from a * given key in TLS. This PRF is defined in RFC 2246, Chapter 5. */ -int tls_prf(const u8 *secret, size_t secret_len, const char *label, - const u8 *seed, size_t seed_len, u8 *out, size_t outlen) +int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label, + const u8 *seed, size_t seed_len, u8 *out, size_t outlen) { size_t L_S1, L_S2, i; const u8 *S1, *S2; diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h index c1a6233..f0c1a5f 100644 --- a/src/crypto/sha1.h +++ b/src/crypto/sha1.h @@ -25,9 +25,9 @@ int sha1_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 sha1_t_prf(const u8 *key, size_t key_len, const char *label, const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len); -int __must_check tls_prf(const u8 *secret, size_t secret_len, - const char *label, const u8 *seed, size_t seed_len, - u8 *out, size_t outlen); +int __must_check tls_prf_sha1_md5(const u8 *secret, size_t secret_len, + const char *label, const u8 *seed, + size_t seed_len, u8 *out, size_t outlen); int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, int iterations, u8 *buf, size_t buflen); #endif /* SHA1_H */ diff --git a/src/crypto/sha256-internal.c b/src/crypto/sha256-internal.c index b061373..ef5751d 100644 --- a/src/crypto/sha256-internal.c +++ b/src/crypto/sha256-internal.c @@ -1,6 +1,6 @@ /* * SHA-256 hash implementation and interface functions - * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,19 +16,9 @@ #include "common.h" #include "sha256.h" +#include "sha256_i.h" #include "crypto.h" -struct sha256_state { - u64 length; - u32 state[8], curlen; - u8 buf[64]; -}; - -static void sha256_init(struct sha256_state *md); -static int sha256_process(struct sha256_state *md, const unsigned char *in, - unsigned long inlen); -static int sha256_done(struct sha256_state *md, unsigned char *out); - /** * sha256_vector - SHA256 hash for data vector @@ -137,7 +127,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf) /* Initialize the hash state */ -static void sha256_init(struct sha256_state *md) +void sha256_init(struct sha256_state *md) { md->curlen = 0; md->length = 0; @@ -158,32 +148,31 @@ static void sha256_init(struct sha256_state *md) @param inlen The length of the data (octets) @return CRYPT_OK if successful */ -static int sha256_process(struct sha256_state *md, const unsigned char *in, - unsigned long inlen) +int sha256_process(struct sha256_state *md, const unsigned char *in, + unsigned long inlen) { unsigned long n; -#define block_size 64 - if (md->curlen > sizeof(md->buf)) + if (md->curlen >= sizeof(md->buf)) return -1; while (inlen > 0) { - if (md->curlen == 0 && inlen >= block_size) { + if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) { if (sha256_compress(md, (unsigned char *) in) < 0) return -1; - md->length += block_size * 8; - in += block_size; - inlen -= block_size; + md->length += SHA256_BLOCK_SIZE * 8; + in += SHA256_BLOCK_SIZE; + inlen -= SHA256_BLOCK_SIZE; } else { - n = MIN(inlen, (block_size - md->curlen)); + n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen)); os_memcpy(md->buf + md->curlen, in, n); md->curlen += n; in += n; inlen -= n; - if (md->curlen == block_size) { + if (md->curlen == SHA256_BLOCK_SIZE) { if (sha256_compress(md, md->buf) < 0) return -1; - md->length += 8 * block_size; + md->length += 8 * SHA256_BLOCK_SIZE; md->curlen = 0; } } @@ -199,7 +188,7 @@ static int sha256_process(struct sha256_state *md, const unsigned char *in, @param out [out] The destination of the hash (32 bytes) @return CRYPT_OK if successful */ -static int sha256_done(struct sha256_state *md, unsigned char *out) +int sha256_done(struct sha256_state *md, unsigned char *out) { int i; @@ -217,14 +206,14 @@ static int sha256_done(struct sha256_state *md, unsigned char *out) * encoding like normal. */ if (md->curlen > 56) { - while (md->curlen < 64) { + while (md->curlen < SHA256_BLOCK_SIZE) { md->buf[md->curlen++] = (unsigned char) 0; } sha256_compress(md, md->buf); md->curlen = 0; } - /* pad upto 56 bytes of zeroes */ + /* pad up to 56 bytes of zeroes */ while (md->curlen < 56) { md->buf[md->curlen++] = (unsigned char) 0; } diff --git a/src/crypto/sha256-tlsprf.c b/src/crypto/sha256-tlsprf.c new file mode 100644 index 0000000..6763c96 --- /dev/null +++ b/src/crypto/sha256-tlsprf.c @@ -0,0 +1,72 @@ +/* + * TLS PRF P_SHA256 + * Copyright (c) 2011, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "sha256.h" + + +/** + * tls_prf_sha256 - Pseudo-Random Function for TLS v1.2 (P_SHA256, RFC 5246) + * @secret: Key for PRF + * @secret_len: Length of the key in bytes + * @label: A unique label for each purpose of the PRF + * @seed: Seed value to bind into the key + * @seed_len: Length of the seed + * @out: Buffer for the generated pseudo-random key + * @outlen: 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 in TLS. This PRF is defined in RFC 2246, Chapter 5. + */ +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) +{ + size_t clen; + u8 A[SHA256_MAC_LEN]; + u8 P[SHA256_MAC_LEN]; + size_t pos; + const unsigned char *addr[3]; + size_t len[3]; + + addr[0] = A; + len[0] = SHA256_MAC_LEN; + addr[1] = (unsigned char *) label; + len[1] = os_strlen(label); + addr[2] = seed; + len[2] = seed_len; + + /* + * RFC 5246, Chapter 5 + * A(0) = seed, A(i) = HMAC(secret, A(i-1)) + * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + .. + * PRF(secret, label, seed) = P_SHA256(secret, label + seed) + */ + + hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A); + + pos = 0; + while (pos < outlen) { + hmac_sha256_vector(secret, secret_len, 3, addr, len, P); + hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A); + + clen = outlen - pos; + if (clen > SHA256_MAC_LEN) + clen = SHA256_MAC_LEN; + os_memcpy(out + pos, P, clen); + pos += clen; + } +} diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h index dc597f0..b1ce6af 100644 --- a/src/crypto/sha256.h +++ b/src/crypto/sha256.h @@ -1,6 +1,6 @@ /* * SHA256 hash implementation and interface functions - * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -23,5 +23,8 @@ void 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 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); #endif /* SHA256_H */ diff --git a/src/crypto/sha256_i.h b/src/crypto/sha256_i.h new file mode 100644 index 0000000..20ae488 --- /dev/null +++ b/src/crypto/sha256_i.h @@ -0,0 +1,31 @@ +/* + * SHA-256 internal definitions + * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef SHA256_I_H +#define SHA256_I_H + +#define SHA256_BLOCK_SIZE 64 + +struct sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[SHA256_BLOCK_SIZE]; +}; + +void sha256_init(struct sha256_state *md); +int sha256_process(struct sha256_state *md, const unsigned char *in, + unsigned long inlen); +int sha256_done(struct sha256_state *md, unsigned char *out); + +#endif /* SHA256_I_H */ diff --git a/src/crypto/tls.h b/src/crypto/tls.h index 0928b5b..d9d88cb 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -24,8 +24,6 @@ struct tls_keys { size_t client_random_len; const u8 *server_random; size_t server_random_len; - const u8 *inner_secret; /* TLS/IA inner secret */ - size_t inner_secret_len; }; enum tls_event { @@ -72,6 +70,7 @@ struct tls_config { const char *pkcs11_engine_path; const char *pkcs11_module_path; int fips_mode; + int cert_in_cb; void (*event_cb)(void *ctx, enum tls_event ev, union tls_event_data *data); @@ -114,7 +113,6 @@ struct tls_config { * specific for now) * @cert_id: the certificate's id when using engine * @ca_cert_id: the CA certificate's id when using engine - * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1) * @flags: Parameter options (TLS_CONN_*) * * TLS connection parameters to be configured with tls_connection_set_params() @@ -142,7 +140,6 @@ struct tls_connection_params { const char *dh_file; const u8 *dh_blob; size_t dh_blob_len; - int tls_ia; /* OpenSSL specific variables */ int engine; @@ -282,20 +279,6 @@ int __must_check tls_connection_set_verify(void *tls_ctx, int verify_peer); /** - * tls_connection_set_ia - Set TLS/IA parameters - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @tls_ia: 1 = enable TLS/IA - * Returns: 0 on success, -1 on failure - * - * This function is used to configure TLS/IA in server mode where - * tls_connection_set_params() is not used. - */ -int __must_check tls_connection_set_ia(void *tls_ctx, - struct tls_connection *conn, - int tls_ia); - -/** * tls_connection_get_keys - Get master key and random data from TLS connection * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() @@ -322,7 +305,7 @@ int __must_check tls_connection_get_keys(void *tls_ctx, * not exported from the TLS library, tls_connection_prf() is required so that * further keying material can be derived from the master secret. If not * implemented, the function will still need to be defined, but it can just - * return -1. Example implementation of this function is in tls_prf() function + * return -1. 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). */ @@ -364,6 +347,12 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx, const struct wpabuf *in_data, struct wpabuf **appl_data); +struct wpabuf * tls_connection_handshake2(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data, + int *more_data_needed); + /** * tls_connection_server_handshake - Process TLS handshake (server side) * @tls_ctx: TLS context data from tls_init() @@ -409,6 +398,11 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data); +struct wpabuf * tls_connection_decrypt2(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + int *more_data_needed); + /** * tls_connection_resumed - Was session resumption used * @tls_ctx: TLS context data from tls_init() @@ -514,7 +508,6 @@ int tls_connection_get_write_alerts(void *tls_ctx, int tls_connection_get_keyblock_size(void *tls_ctx, struct tls_connection *conn); -#define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */ /** * tls_capabilities - Get supported TLS capabilities * @tls_ctx: TLS context data from tls_init() @@ -522,42 +515,6 @@ int tls_connection_get_keyblock_size(void *tls_ctx, */ unsigned int tls_capabilities(void *tls_ctx); -/** - * tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished - * Returns: Encrypted TLS/IA data, %NULL on failure - * - * This function is used to send the TLS/IA end phase message, e.g., when the - * EAP server completes EAP-TTLSv1. - */ -struct wpabuf * tls_connection_ia_send_phase_finished( - void *tls_ctx, struct tls_connection *conn, int final); - -/** - * tls_connection_ia_final_phase_finished - Has final phase been completed - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1 - * on failure - */ -int __must_check tls_connection_ia_final_phase_finished( - void *tls_ctx, struct tls_connection *conn); - -/** - * tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @key: Session key material (session_key vectors with 2-octet length), or - * %NULL if no session key was generating in the current phase - * @key_len: Length of session key material - * Returns: 0 on success, -1 on failure - */ -int __must_check tls_connection_ia_permute_inner_secret( - void *tls_ctx, struct tls_connection *conn, - const u8 *key, size_t key_len); - typedef int (*tls_session_ticket_cb) (void *ctx, const u8 *ticket, size_t len, const u8 *client_random, const u8 *server_random, u8 *master_secret); diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index c3a7358..afa5268 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -1,6 +1,6 @@ /* * SSL/TLS interface functions for GnuTLS - * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,28 +19,12 @@ #include <gnutls/pkcs12.h> #endif /* PKCS12_FUNCS */ -#ifdef CONFIG_GNUTLS_EXTRA -#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 -#define GNUTLS_IA -#include <gnutls/extra.h> -#if LIBGNUTLS_VERSION_NUMBER == 0x010302 -/* This function is not included in the current gnutls/extra.h even though it - * should be, so define it here as a workaround for the time being. */ -int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum); -#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */ -#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ -#endif /* CONFIG_GNUTLS_EXTRA */ - #include "common.h" #include "tls.h" -#ifndef TLS_RANDOM_SIZE -#define TLS_RANDOM_SIZE 32 -#endif -#ifndef TLS_MASTER_SIZE -#define TLS_MASTER_SIZE 48 -#endif +#define WPA_TLS_RANDOM_SIZE 32 +#define WPA_TLS_MASTER_SIZE 48 #if LIBGNUTLS_VERSION_NUMBER < 0x010302 @@ -77,9 +61,9 @@ typedef struct { gnutls_mac_algorithm_t write_mac_algorithm; gnutls_compression_method_t write_compression_algorithm; cipher_suite_st current_cipher_suite; - opaque master_secret[TLS_MASTER_SIZE]; - opaque client_random[TLS_RANDOM_SIZE]; - opaque server_random[TLS_RANDOM_SIZE]; + opaque master_secret[WPA_TLS_MASTER_SIZE]; + opaque client_random[WPA_TLS_RANDOM_SIZE]; + opaque server_random[WPA_TLS_RANDOM_SIZE]; /* followed by stuff we are not interested in */ } security_parameters_st; @@ -118,21 +102,6 @@ struct tls_connection { int params_set; gnutls_certificate_credentials_t xcred; - - int tls_ia; - int final_phase_finished; - -#ifdef GNUTLS_IA - gnutls_ia_server_credentials_t iacred_srv; - gnutls_ia_client_credentials_t iacred_cli; - - /* Session keys generated in the current phase for inner secret - * permutation before generating/verifying PhaseFinished. */ - u8 *session_keys; - size_t session_keys_len; - - u8 inner_secret[TLS_MASTER_SIZE]; -#endif /* GNUTLS_IA */ }; @@ -285,8 +254,12 @@ static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf, static int tls_gnutls_init_session(struct tls_global *global, struct tls_connection *conn) { +#if LIBGNUTLS_VERSION_NUMBER >= 0x020200 + const char *err; +#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */ const int cert_types[2] = { GNUTLS_CRT_X509, 0 }; const int protos[2] = { GNUTLS_TLS1, 0 }; +#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */ int ret; ret = gnutls_init(&conn->session, @@ -301,6 +274,15 @@ static int tls_gnutls_init_session(struct tls_global *global, if (ret < 0) goto fail; +#if LIBGNUTLS_VERSION_NUMBER >= 0x020200 + ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0", + &err); + if (ret < 0) { + wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at " + "'%s'", err); + goto fail; + } +#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */ ret = gnutls_certificate_type_set_priority(conn->session, cert_types); if (ret < 0) goto fail; @@ -308,6 +290,7 @@ static int tls_gnutls_init_session(struct tls_global *global, ret = gnutls_protocol_set_priority(conn->session, protos); if (ret < 0) goto fail; +#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */ gnutls_transport_set_pull_function(conn->session, tls_pull_func); gnutls_transport_set_push_function(conn->session, tls_push_func); @@ -364,17 +347,6 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) if (conn == NULL) return; -#ifdef GNUTLS_IA - if (conn->iacred_srv) - gnutls_ia_free_server_credentials(conn->iacred_srv); - if (conn->iacred_cli) - gnutls_ia_free_client_credentials(conn->iacred_cli); - if (conn->session_keys) { - os_memset(conn->session_keys, 0, conn->session_keys_len); - os_free(conn->session_keys); - } -#endif /* GNUTLS_IA */ - gnutls_certificate_free_credentials(conn->xcred); gnutls_deinit(conn->session); os_free(conn->pre_shared_secret); @@ -407,14 +379,6 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) wpabuf_free(conn->push_buf); conn->push_buf = NULL; conn->established = 0; - conn->final_phase_finished = 0; -#ifdef GNUTLS_IA - if (conn->session_keys) { - os_memset(conn->session_keys, 0, conn->session_keys_len); - os_free(conn->session_keys); - } - conn->session_keys_len = 0; -#endif /* GNUTLS_IA */ gnutls_deinit(conn->session); if (tls_gnutls_init_session(global, conn)) { @@ -597,11 +561,13 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5); } +#if LIBGNUTLS_VERSION_NUMBER >= 0x020800 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) { gnutls_certificate_set_verify_flags( conn->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS); } +#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */ } if (params->client_cert && params->private_key) { @@ -646,7 +612,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, } } - conn->tls_ia = params->tls_ia; conn->params_set = 1; ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, @@ -656,28 +621,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, gnutls_strerror(ret)); } -#ifdef GNUTLS_IA - if (conn->iacred_cli) - gnutls_ia_free_client_credentials(conn->iacred_cli); - - ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli); - if (ret) { - wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s", - gnutls_strerror(ret)); - return -1; - } - - ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA, - conn->iacred_cli); - if (ret) { - wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s", - gnutls_strerror(ret)); - gnutls_ia_free_client_credentials(conn->iacred_cli); - conn->iacred_cli = NULL; - return -1; - } -#endif /* GNUTLS_IE */ - return ret; } @@ -729,11 +672,13 @@ int tls_global_set_params(void *tls_ctx, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5); } +#if LIBGNUTLS_VERSION_NUMBER >= 0x020800 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) { gnutls_certificate_set_verify_flags( global->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS); } +#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */ } if (params->client_cert && params->private_key) { @@ -822,10 +767,11 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, os_memset(keys, 0, sizeof(*keys)); +#if LIBGNUTLS_VERSION_NUMBER < 0x020c00 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK sec = &conn->session->security_parameters; keys->master_key = sec->master_secret; - keys->master_key_len = TLS_MASTER_SIZE; + keys->master_key_len = WPA_TLS_MASTER_SIZE; keys->client_random = sec->client_random; keys->server_random = sec->server_random; #else /* GNUTLS_INTERNAL_STRUCTURE_HACK */ @@ -835,16 +781,12 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, (u8 *) gnutls_session_get_server_random(conn->session); /* No access to master_secret */ #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ +#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */ -#ifdef GNUTLS_IA - gnutls_ia_extract_inner_secret(conn->session, - (char *) conn->inner_secret); - keys->inner_secret = conn->inner_secret; - keys->inner_secret_len = TLS_MASTER_SIZE; -#endif /* GNUTLS_IA */ - - keys->client_random_len = TLS_RANDOM_SIZE; - keys->server_random_len = TLS_RANDOM_SIZE; +#if LIBGNUTLS_VERSION_NUMBER < 0x020c00 + keys->client_random_len = WPA_TLS_RANDOM_SIZE; + keys->server_random_len = WPA_TLS_RANDOM_SIZE; +#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */ return 0; } @@ -883,11 +825,13 @@ static int tls_connection_verify_peer(struct tls_connection *conn, if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) { wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted"); + *err = GNUTLS_A_INTERNAL_ERROR; if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { wpa_printf(MSG_INFO, "TLS: Certificate uses insecure " "algorithm"); *err = GNUTLS_A_INSUFFICIENT_SECURITY; } +#if LIBGNUTLS_VERSION_NUMBER >= 0x020800 if (status & GNUTLS_CERT_NOT_ACTIVATED) { wpa_printf(MSG_INFO, "TLS: Certificate not yet " "activated"); @@ -897,6 +841,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn, wpa_printf(MSG_INFO, "TLS: Certificate expired"); *err = GNUTLS_A_CERTIFICATE_EXPIRED; } +#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */ return -1; } @@ -988,7 +933,7 @@ static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn) wpabuf_size(ad)); wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res); if (res < 0) { - wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " + wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " "(%s)", __func__, (int) res, gnutls_strerror(res)); wpabuf_free(ad); @@ -1062,20 +1007,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx, goto out; } -#ifdef CONFIG_GNUTLS_EXTRA - if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) { - wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation"); - conn->failed++; - return NULL; - } -#endif /* CONFIG_GNUTLS_EXTRA */ - - if (conn->tls_ia) - wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake"); - else { - wpa_printf(MSG_DEBUG, "TLS: Handshake completed " - "successfully"); - } + wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully"); conn->established = 1; if (conn->push_buf == NULL) { /* Need to return something to get final TLS ACK. */ @@ -1122,12 +1054,6 @@ struct wpabuf * tls_connection_encrypt(void *tls_ctx, ssize_t res; struct wpabuf *buf; -#ifdef GNUTLS_IA - if (conn->tls_ia) - res = gnutls_ia_send(conn->session, wpabuf_head(in_data), - wpabuf_len(in_data)); - else -#endif /* GNUTLS_IA */ res = gnutls_record_send(conn->session, wpabuf_head(in_data), wpabuf_len(in_data)); if (res < 0) { @@ -1170,65 +1096,6 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx, if (out == NULL) return NULL; -#ifdef GNUTLS_IA - if (conn->tls_ia) { - res = gnutls_ia_recv(conn->session, wpabuf_mhead(out), - wpabuf_size(out)); - if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED || - res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) { - int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED; - wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished", - __func__, final ? "Final" : "Intermediate"); - - res = gnutls_ia_permute_inner_secret( - conn->session, conn->session_keys_len, - (char *) conn->session_keys); - if (conn->session_keys) { - os_memset(conn->session_keys, 0, - conn->session_keys_len); - os_free(conn->session_keys); - } - conn->session_keys = NULL; - conn->session_keys_len = 0; - if (res) { - wpa_printf(MSG_DEBUG, "%s: Failed to permute " - "inner secret: %s", - __func__, gnutls_strerror(res)); - wpabuf_free(out); - return NULL; - } - - res = gnutls_ia_verify_endphase(conn->session, - wpabuf_head(out)); - if (res == 0) { - wpa_printf(MSG_DEBUG, "%s: Correct endphase " - "checksum", __func__); - } else { - wpa_printf(MSG_INFO, "%s: Endphase " - "verification failed: %s", - __func__, gnutls_strerror(res)); - wpabuf_free(out); - return NULL; - } - - if (final) - conn->final_phase_finished = 1; - - return out; - } - - if (res < 0) { - wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " - "(%s)", __func__, (int) res, - gnutls_strerror(res)); - wpabuf_free(out); - return NULL; - } - wpabuf_put(out, res); - return out; - } -#endif /* GNUTLS_IA */ - res = gnutls_record_recv(conn->session, wpabuf_mhead(out), wpabuf_size(out)); if (res < 0) { @@ -1319,133 +1186,7 @@ int tls_connection_get_keyblock_size(void *tls_ctx, unsigned int tls_capabilities(void *tls_ctx) { - unsigned int capa = 0; - -#ifdef GNUTLS_IA - capa |= TLS_CAPABILITY_IA; -#endif /* GNUTLS_IA */ - - return capa; -} - - -int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, - int tls_ia) -{ -#ifdef GNUTLS_IA - int ret; - - if (conn == NULL) - return -1; - - conn->tls_ia = tls_ia; - if (!tls_ia) - return 0; - - ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv); - if (ret) { - wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s", - gnutls_strerror(ret)); - return -1; - } - - ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA, - conn->iacred_srv); - if (ret) { - wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s", - gnutls_strerror(ret)); - gnutls_ia_free_server_credentials(conn->iacred_srv); - conn->iacred_srv = NULL; - return -1; - } - - return 0; -#else /* GNUTLS_IA */ - return -1; -#endif /* GNUTLS_IA */ -} - - -struct wpabuf * tls_connection_ia_send_phase_finished( - void *tls_ctx, struct tls_connection *conn, int final) -{ -#ifdef GNUTLS_IA - int ret; - struct wpabuf *buf; - - if (conn == NULL || conn->session == NULL || !conn->tls_ia) - return NULL; - - ret = gnutls_ia_permute_inner_secret(conn->session, - conn->session_keys_len, - (char *) conn->session_keys); - if (conn->session_keys) { - os_memset(conn->session_keys, 0, conn->session_keys_len); - os_free(conn->session_keys); - } - conn->session_keys = NULL; - conn->session_keys_len = 0; - if (ret) { - wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s", - __func__, gnutls_strerror(ret)); - return NULL; - } - - ret = gnutls_ia_endphase_send(conn->session, final); - if (ret) { - wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s", - __func__, gnutls_strerror(ret)); - return NULL; - } - - buf = conn->push_buf; - conn->push_buf = NULL; - return buf; -#else /* GNUTLS_IA */ - return NULL; -#endif /* GNUTLS_IA */ -} - - -int tls_connection_ia_final_phase_finished(void *tls_ctx, - struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - - return conn->final_phase_finished; -} - - -int tls_connection_ia_permute_inner_secret(void *tls_ctx, - struct tls_connection *conn, - const u8 *key, size_t key_len) -{ -#ifdef GNUTLS_IA - if (conn == NULL || !conn->tls_ia) - return -1; - - if (conn->session_keys) { - os_memset(conn->session_keys, 0, conn->session_keys_len); - os_free(conn->session_keys); - } - conn->session_keys_len = 0; - - if (key) { - conn->session_keys = os_malloc(key_len); - if (conn->session_keys == NULL) - return -1; - os_memcpy(conn->session_keys, key, key_len); - conn->session_keys_len = key_len; - } else { - conn->session_keys = NULL; - conn->session_keys_len = 0; - } - return 0; -#else /* GNUTLS_IA */ - return -1; -#endif /* GNUTLS_IA */ } diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index cc165f6..f5e31d9 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -290,13 +290,6 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, } -int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, - int tls_ia) -{ - return -1; -} - - int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, struct tls_keys *keys) { @@ -339,6 +332,17 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx, const struct wpabuf *in_data, struct wpabuf **appl_data) { + return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data, + NULL); +} + + +struct wpabuf * tls_connection_handshake2(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data, + int *need_more_data) +{ #ifdef CONFIG_TLS_INTERNAL_CLIENT u8 *res, *ad; size_t res_len, ad_len; @@ -351,7 +355,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx, res = tlsv1_client_handshake(conn->client, in_data ? wpabuf_head(in_data) : NULL, in_data ? wpabuf_len(in_data) : 0, - &res_len, &ad, &ad_len); + &res_len, &ad, &ad_len, need_more_data); if (res == NULL) return NULL; out = wpabuf_alloc_ext_data(res, res_len); @@ -462,23 +466,23 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { + return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL); +} + + +struct wpabuf * tls_connection_decrypt2(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + int *need_more_data) +{ + if (need_more_data) + *need_more_data = 0; + #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { - struct wpabuf *buf; - int res; - buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); - if (buf == NULL) - return NULL; - res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data), - wpabuf_len(in_data), - wpabuf_mhead(buf), - wpabuf_size(buf)); - if (res < 0) { - wpabuf_free(buf); - return NULL; - } - wpabuf_put(buf, res); - return buf; + return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data), + wpabuf_len(in_data), + need_more_data); } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER @@ -611,28 +615,6 @@ unsigned int tls_capabilities(void *tls_ctx) } -struct wpabuf * tls_connection_ia_send_phase_finished( - void *tls_ctx, struct tls_connection *conn, int final) -{ - return NULL; -} - - -int tls_connection_ia_final_phase_finished(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_ia_permute_inner_secret(void *tls_ctx, - struct tls_connection *conn, - const u8 *key, size_t key_len) -{ - return -1; -} - - int tls_connection_set_session_ticket_cb(void *tls_ctx, struct tls_connection *conn, tls_session_ticket_cb cb, diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c index 0c836bb..927edf5 100644 --- a/src/crypto/tls_none.c +++ b/src/crypto/tls_none.c @@ -84,13 +84,6 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, } -int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, - int tls_ia) -{ - return -1; -} - - int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, struct tls_keys *keys) { @@ -205,25 +198,3 @@ unsigned int tls_capabilities(void *tls_ctx) { return 0; } - - -struct wpabuf * tls_connection_ia_send_phase_finished( - void *tls_ctx, struct tls_connection *conn, int final) -{ - return NULL; -} - - -int tls_connection_ia_final_phase_finished(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_ia_permute_inner_secret(void *tls_ctx, - struct tls_connection *conn, - const u8 *key, size_t key_len) -{ - return -1; -} diff --git a/src/crypto/tls_nss.c b/src/crypto/tls_nss.c index ad834b6..09a1e73 100644 --- a/src/crypto/tls_nss.c +++ b/src/crypto/tls_nss.c @@ -419,13 +419,6 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, } -int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, - int tls_ia) -{ - return -1; -} - - int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, struct tls_keys *keys) { @@ -649,28 +642,6 @@ unsigned int tls_capabilities(void *tls_ctx) } -struct wpabuf * tls_connection_ia_send_phase_finished( - void *tls_ctx, struct tls_connection *conn, int final) -{ - return NULL; -} - - -int tls_connection_ia_final_phase_finished(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_ia_permute_inner_secret(void *tls_ctx, - struct tls_connection *conn, - const u8 *key, size_t key_len) -{ - return -1; -} - - int tls_connection_set_session_ticket_cb(void *tls_ctx, struct tls_connection *conn, tls_session_ticket_cb cb, diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 14ff87e..8374096 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -59,6 +59,7 @@ struct tls_global { void (*event_cb)(void *ctx, enum tls_event ev, union tls_event_data *data); void *cb_ctx; + int cert_in_cb; }; static struct tls_global *tls_global = NULL; @@ -694,6 +695,7 @@ void * tls_init(const struct tls_config *conf) if (conf) { tls_global->event_cb = conf->event_cb; tls_global->cb_ctx = conf->cb_ctx; + tls_global->cert_in_cb = conf->cert_in_cb; } #ifdef CONFIG_FIPS @@ -1144,7 +1146,7 @@ static void openssl_tls_cert_event(struct tls_connection *conn, return; os_memset(&ev, 0, sizeof(ev)); - if (conn->cert_probe) { + if (conn->cert_probe || tls_global->cert_in_cb) { cert = get_x509_cert(err_cert); ev.peer_cert.cert = cert; } @@ -1661,6 +1663,7 @@ static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert) if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert, SSL_FILETYPE_ASN1) != 1 && + SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 && SSL_CTX_use_certificate_file(ssl_ctx, client_cert, SSL_FILETYPE_PEM) != 1) { tls_show_errors(MSG_INFO, __func__, @@ -2809,35 +2812,6 @@ unsigned int tls_capabilities(void *tls_ctx) } -int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, - int tls_ia) -{ - return -1; -} - - -struct wpabuf * tls_connection_ia_send_phase_finished( - void *tls_ctx, struct tls_connection *conn, int final) -{ - return NULL; -} - - -int tls_connection_ia_final_phase_finished(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_ia_permute_inner_secret(void *tls_ctx, - struct tls_connection *conn, - const u8 *key, size_t key_len) -{ - return -1; -} - - #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) /* Pre-shared secred requires a patch to openssl, so this function is * commented out unless explicitly needed for EAP-FAST in order to be able to diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c index 4a94e99..a33d24e 100644 --- a/src/crypto/tls_schannel.c +++ b/src/crypto/tls_schannel.c @@ -736,32 +736,3 @@ unsigned int tls_capabilities(void *tls_ctx) { return 0; } - - -int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, - int tls_ia) -{ - return -1; -} - - -struct wpabuf * tls_connection_ia_send_phase_finished( - void *tls_ctx, struct tls_connection *conn, int final); -{ - return NULL; -} - - -int tls_connection_ia_final_phase_finished(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_ia_permute_inner_secret(void *tls_ctx, - struct tls_connection *conn, - const u8 *key, size_t key_len) -{ - return -1; -} diff --git a/src/drivers/Apple80211.h b/src/drivers/Apple80211.h deleted file mode 100644 index 2a612e7..0000000 --- a/src/drivers/Apple80211.h +++ /dev/null @@ -1,156 +0,0 @@ -#ifndef APPLE80211_H -#define APPLE80211_H - -/* - * Apple80211 framework definitions - * This is an undocumented interface and the definitions here are based on - * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and - * whatever related information can be found with google and experiments ;-). - */ - -typedef struct __WirelessRef *WirelessRef; -typedef SInt32 WirelessError; -#define errWirelessNoError 0 - -typedef struct WirelessInfo { - UInt16 link_qual; - UInt16 comms_qual; - UInt16 signal; - UInt16 noise; - UInt16 port_stat; - UInt16 client_mode; - UInt16 res1; - UInt16 power; - UInt16 res2; - UInt8 bssID[6]; - UInt8 ssid[34]; -} WirelessInfo; - -typedef struct WirelessInfo2 { - /* TODO - these are probably not in correct order or complete */ - WirelessInfo info1; - UInt8 macAddress[6]; -} WirelessInfo2; - -typedef struct WirelessNetworkInfo { - UInt16 channel; - UInt16 noise; - UInt16 signal; - UInt8 bssid[6]; - UInt16 beacon_int; - UInt16 capability; - UInt16 ssid_len; - UInt8 ssid[32]; -} WirelessNetworkInfo; - -typedef int wirelessKeyType; /* TODO */ - -int WirelessIsAvailable(void); -WirelessError WirelessAttach(WirelessRef *ref, UInt32 res); -WirelessError WirelessDetach(WirelessRef ref); -WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes, - void *out_ptr, int out_bytes); -WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled); -WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled); -WirelessError WirelessSetPower(WirelessRef ref, UInt8 power); -WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power); -WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info); -WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info); -WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results, - UInt32 strip_dups); -WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results, - CFArrayRef *ibss_results, UInt32 strip_dups); -WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results, - UInt32 strip_dups, CFStringRef ssid); -WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid, - UInt32 strip_dups, CFArrayRef *results); -WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid); -WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid, - CFStringRef passwd); -WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid); -/* - * Set WEP key - * ref: wireless reference from WirelessAttach() - * type: ? - * key_idx: 0..3 - * key_len: 13 for WEP-104 or 0 for clearing the key - * key: Pointer to the key or %NULL if key_len = 0 - */ -WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type, - int key_idx, int key_len, - const unsigned char *key); -/* - * Set WPA key (e.g., PMK for 4-way handshake) - * ref: wireless reference from WirelessAttach() - * type: 0..4; 1 = PMK - * key_len: 16, 32, or 0 - * key: Pointer to the key or %NULL if key_len = 0 - */ -WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type, - int key_len, const unsigned char *key); -WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid, - CFStringRef key); -WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res, - CFStringRef key); -WirelessError WirelessDisassociate(WirelessRef ref); - -/* - * Get a copy of scan results for the given SSID - * The returned dictionary includes following entries: - * beaconInterval: CFNumber(kCFNumberSInt32Type) - * SSID: CFData buffer of the SSID - * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2 - * name: Name of the network (SSID string) - * BSSID: CFData buffer of the BSSID - * channel: CFNumber(kCFNumberSInt32Type) - * signal: CFNumber(kCFNumberSInt32Type) - * appleIE: CFData - * WPSNOPINRequired: CFBoolean - * noise: CFNumber(kCFNumberSInt32Type) - * capability: CFNumber(kCFNumberSInt32Type) - * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type) - * appleIE_Version: CFNumber(kCFNumberSInt32Type) - * appleIE_Robust: CFBoolean - * WPSConfigured: CFBoolean - * scanWasDirected: CFBoolean - * appleIE_Product: CFNumber(kCFNumberSInt32Type) - * authModes: CFArray of CFNumber(kCFNumberSInt32Type) - * multiCipher: CFNumber(kCFNumberSInt32Type) - */ -CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid); - -/* - * Get information about the current association - * The returned dictionary includes following entries: - * keyData: CFData buffer of the key (e.g., 32-octet PSK) - * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP? - * channel: CFNumber(kCFNumberSInt32Type) - * isIBSS: CFBoolean - * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open, - * 129 = WPA2-Enterprise - * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2 - * SSID: CFData buffer of the SSID - * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP? - */ -CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref); - -WirelessError WirelessConfigure(WirelessRef ref); - -/* - * Get ASP information - * The returned dictionary includes following entries: - * Version: version number (e.g., 3.0) - * Channel: channel (e.g., 1) - * Vendor: vendor (e.g., 2) - */ -CFDictionaryRef WirelessGetInfoASP(void); - -/* - * Get a copy of the interface dictionary - * The returned dictionary has a key,value pairs for wireless interfaces. - * The key is the interface name and the value is the driver identifier, e.g., - * en1: com.apple.driver.AirPort.Atheros - */ -CFDictionaryRef WirelessCopyInterfaceDict(void); - -#endif /* APPLE80211_H */ diff --git a/src/drivers/MobileApple80211.c b/src/drivers/MobileApple80211.c deleted file mode 100644 index ce004fe..0000000 --- a/src/drivers/MobileApple80211.c +++ /dev/null @@ -1,189 +0,0 @@ -#include "includes.h" -#include <dlfcn.h> - -#include "common.h" - -#include <CoreFoundation/CoreFoundation.h> -#include "MobileApple80211.h" - -/* - * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid - * having to link with full Preferences.framework. - */ - -static void *aeropuerto = NULL; - - -int _Apple80211Initialized(void) -{ - return aeropuerto ? 1 : 0; -} - - -static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL; - -int Apple80211Open(Apple80211Ref *ctx) -{ - return __Apple80211Open(ctx); -} - - -static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL; - -int Apple80211Close(Apple80211Ref ctx) -{ - return __Apple80211Close(ctx); -} - - -static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list) - = NULL; - -int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list) -{ - return __Apple80211GetIfListCopy(handle, list); -} - - -static int (*__Apple80211BindToInterface)(Apple80211Ref handle, - CFStringRef interface) = NULL; - -int Apple80211BindToInterface(Apple80211Ref handle, - CFStringRef interface) -{ - return __Apple80211BindToInterface(handle, interface); -} - - -static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle, - CFStringRef *name) = NULL; - -int Apple80211GetInterfaceNameCopy(Apple80211Ref handle, - CFStringRef *name) -{ - return __Apple80211GetInterfaceNameCopy(handle, name); -} - - -static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle, - CFDictionaryRef *info) = NULL; - -int Apple80211GetInfoCopy(Apple80211Ref handle, - CFDictionaryRef *info) -{ - return __Apple80211GetInfoCopy(handle, info); -} - - -static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL; - -int Apple80211GetPower(Apple80211Ref handle, char *pwr) -{ - return __Apple80211GetPower(handle, pwr); -} - - -static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL; - -int Apple80211SetPower(Apple80211Ref handle, char pwr) -{ - return __Apple80211SetPower(handle, pwr); -} - - -static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list, - CFDictionaryRef parameters) = NULL; - -int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list, - CFDictionaryRef parameters) -{ - return __Apple80211Scan(handle, list, parameters); -} - - -static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss, - CFStringRef password) = NULL; - -int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss, - CFStringRef password) -{ - return __Apple80211Associate(handle, bss, password); -} - - -static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle, - CFDictionaryRef bss, - CFStringRef password, - CFDictionaryRef *info) = - NULL; - -int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss, - CFStringRef password, CFDictionaryRef *info) -{ - return __Apple80211AssociateAndCopyInfo(handle, bss, password, info); -} - - -static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field, - CFDictionaryRef arg2, void *value) = NULL; - -int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2, - void *value) -{ - return __Apple80211CopyValue(handle, field, arg2, value); -} - - -#define DLSYM(s) \ -do { \ - __ ## s = dlsym(aeropuerto, #s); \ - if (__ ## s == NULL) { \ - wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \ - "symbol '" #s "' (%s)", dlerror()); \ - err = 1; \ - } \ -} while (0) - - -__attribute__ ((constructor)) -void _Apple80211_constructor(void) -{ - const char *fname = "/System/Library/SystemConfiguration/" - "Aeropuerto.bundle/Aeropuerto"; - int err = 0; - - aeropuerto = dlopen(fname, RTLD_LAZY); - if (!aeropuerto) { - wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s " - "for symbols", fname); - return; - } - - DLSYM(Apple80211Open); - DLSYM(Apple80211Close); - DLSYM(Apple80211GetIfListCopy); - DLSYM(Apple80211BindToInterface); - DLSYM(Apple80211GetInterfaceNameCopy); - DLSYM(Apple80211GetInfoCopy); - DLSYM(Apple80211GetPower); - DLSYM(Apple80211SetPower); - DLSYM(Apple80211Scan); - DLSYM(Apple80211Associate); - DLSYM(Apple80211AssociateAndCopyInfo); - DLSYM(Apple80211CopyValue); - - if (err) { - dlclose(aeropuerto); - aeropuerto = NULL; - } -} - - -__attribute__ ((destructor)) -void _Apple80211_destructor(void) -{ - if (aeropuerto) { - dlclose(aeropuerto); - aeropuerto = NULL; - } -} diff --git a/src/drivers/MobileApple80211.h b/src/drivers/MobileApple80211.h deleted file mode 100644 index 64d439d..0000000 --- a/src/drivers/MobileApple80211.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef MOBILEAPPLE80211_H -#define MOBILEAPPLE80211_H - -/* - * MobileApple80211 interface for iPhone/iPod touch - * These functions are available from Aeropuerto. - */ - -struct Apple80211; -typedef struct Apple80211 *Apple80211Ref; - -int Apple80211Open(Apple80211Ref *ctx); -int Apple80211Close(Apple80211Ref ctx); -int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list); -int Apple80211BindToInterface(Apple80211Ref handle, - CFStringRef interface); -int Apple80211GetInterfaceNameCopy(Apple80211Ref handle, - CFStringRef *name); -int Apple80211GetInfoCopy(Apple80211Ref handle, - CFDictionaryRef *info); -int Apple80211GetPower(Apple80211Ref handle, char *pwr); -int Apple80211SetPower(Apple80211Ref handle, char pwr); - -/* parameters can be NULL; returns scan results in CFArrayRef *list; - * caller will need to free with CFRelease() */ -int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list, - CFDictionaryRef parameters); - -int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss, - CFStringRef password); -int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss, - CFStringRef password, - CFDictionaryRef *info); - -enum { - APPLE80211_VALUE_SSID = 1, - APPLE80211_VALUE_BSSID = 9 -}; - -int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2, - void *value); - -#endif /* MOBILEAPPLE80211_H */ diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h new file mode 100644 index 0000000..6df7160 --- /dev/null +++ b/src/drivers/android_drv.h @@ -0,0 +1,62 @@ +/* + * Android driver interface + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + */ + +#ifndef ANDROID_DRV_H +#define ANDROID_DRV_H + +#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE " + +#define WEXT_CSCAN_AMOUNT 9 + +#define MAX_SSID_LEN 32 + +#define MAX_DRV_CMD_SIZE 248 +#define DRV_NUMBER_SEQUENTIAL_ERRORS 4 + +#define WEXT_PNOSETUP_HEADER "PNOSETUP " +#define WEXT_PNOSETUP_HEADER_SIZE 9 +#define WEXT_PNO_TLV_PREFIX 'S' +#define WEXT_PNO_TLV_VERSION '1' +#define WEXT_PNO_TLV_SUBVERSION '2' +#define WEXT_PNO_TLV_RESERVED '0' +#define WEXT_PNO_VERSION_SIZE 4 +#define WEXT_PNO_AMOUNT 16 +#define WEXT_PNO_SSID_SECTION 'S' +/* SSID header size is SSID section type above + SSID length */ +#define WEXT_PNO_SSID_HEADER_SIZE 2 +#define WEXT_PNO_SCAN_INTERVAL_SECTION 'T' +#define WEXT_PNO_SCAN_INTERVAL_LENGTH 2 +#define WEXT_PNO_SCAN_INTERVAL 30 +/* Scan interval size is scan interval section type + scan interval length + * above */ +#define WEXT_PNO_SCAN_INTERVAL_SIZE (1 + WEXT_PNO_SCAN_INTERVAL_LENGTH) +#define WEXT_PNO_REPEAT_SECTION 'R' +#define WEXT_PNO_REPEAT_LENGTH 1 +#define WEXT_PNO_REPEAT 4 +/* Repeat section size is Repeat section type + Repeat value length above */ +#define WEXT_PNO_REPEAT_SIZE (1 + WEXT_PNO_REPEAT_LENGTH) +#define WEXT_PNO_MAX_REPEAT_SECTION 'M' +#define WEXT_PNO_MAX_REPEAT_LENGTH 1 +#define WEXT_PNO_MAX_REPEAT 3 +/* Max Repeat section size is Max Repeat section type + Max Repeat value length + * above */ +#define WEXT_PNO_MAX_REPEAT_SIZE (1 + WEXT_PNO_MAX_REPEAT_LENGTH) +/* This corresponds to the size of all sections expect SSIDs */ +#define WEXT_PNO_NONSSID_SECTIONS_SIZE \ +(WEXT_PNO_SCAN_INTERVAL_SIZE + WEXT_PNO_REPEAT_SIZE + WEXT_PNO_MAX_REPEAT_SIZE) +/* PNO Max command size is total of header, version, ssid and other sections + + * Null termination */ +#define WEXT_PNO_MAX_COMMAND_SIZE \ + (WEXT_PNOSETUP_HEADER_SIZE + WEXT_PNO_VERSION_SIZE \ + + WEXT_PNO_AMOUNT * (WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN) \ + + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) + +#endif /* ANDROID_DRV_H */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 19f732d..ceed531 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -35,14 +35,6 @@ #define HOSTAPD_CHAN_HT40MINUS 0x00000020 #define HOSTAPD_CHAN_HT40 0x00000040 -#ifdef ANDROID_BRCM_P2P_PATCH -/** - * Monitor interface name is derived from p2p interface name - * We need to reset p2p interface name early to take care of extra character in - */ -#define WPA_MONITOR_IFNAME_PREFIX "m." -#endif - /** * struct hostapd_channel_data - Channel information */ @@ -68,6 +60,8 @@ struct hostapd_channel_data { u8 max_tx_power; }; +#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0) + /** * struct hostapd_hw_modes - Supported hardware mode information */ @@ -111,6 +105,8 @@ struct hostapd_hw_modes { * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters */ u8 a_mpdu_params; + + unsigned int flags; /* HOSTAPD_MODE_FLAG_* */ }; @@ -203,7 +199,7 @@ struct wpa_interface_info { const char *drv_name; }; -#define WPAS_MAX_SCAN_SSIDS 10 +#define WPAS_MAX_SCAN_SSIDS 16 /** * struct wpa_driver_scan_params - Scan parameters @@ -272,6 +268,15 @@ struct wpa_driver_scan_params { * num_filter_ssids - Number of entries in filter_ssids array */ size_t num_filter_ssids; + + /** + * p2p_probe - Used to disable CCK (802.11b) rates for P2P probes + * + * When set, the driver is expected to remove rates 1, 2, 5.5, and 11 + * Mbps from the support rates element(s) in the Probe Request frames + * and not to transmit the frames at any of those rates. + */ + u8 p2p_probe; }; /** @@ -290,6 +295,12 @@ struct wpa_driver_auth_params { size_t wep_key_len[4]; int wep_tx_keyidx; int local_state_change; + + /** + * p2p - Whether this connection is a P2P group + */ + int p2p; + }; enum wps_mode { @@ -353,6 +364,11 @@ struct wpa_driver_associate_params { size_t wpa_ie_len; /** + * wpa_proto - Bitfield of WPA_PROTO_* values to indicate WPA/WPA2 + */ + unsigned int wpa_proto; + + /** * pairwise_suite - Selected pairwise cipher suite * * This is usually ignored if @wpa_ie is used. @@ -502,6 +518,183 @@ struct wpa_driver_associate_params { int uapsd; }; +enum hide_ssid { + NO_SSID_HIDING, + HIDDEN_SSID_ZERO_LEN, + HIDDEN_SSID_ZERO_CONTENTS +}; + +struct wpa_driver_ap_params { + /** + * head - Beacon head from IEEE 802.11 header to IEs before TIM IE + */ + const u8 *head; + + /** + * head_len - Length of the head buffer in octets + */ + size_t head_len; + + /** + * tail - Beacon tail following TIM IE + */ + const u8 *tail; + + /** + * tail_len - Length of the tail buffer in octets + */ + size_t tail_len; + + /** + * dtim_period - DTIM period + */ + int dtim_period; + + /** + * beacon_int - Beacon interval + */ + int beacon_int; + + /** + * basic_rates: -1 terminated array of basic rates in 100 kbps + * + * This parameter can be used to set a specific basic rate set for the + * BSS. If %NULL, default basic rate set is used. + */ + int *basic_rates; + + /** + * proberesp - Probe Response template + * + * This is used by drivers that reply to Probe Requests internally in + * AP mode and require the full Probe Response template. + */ + const u8 *proberesp; + + /** + * proberesp_len - Length of the proberesp buffer in octets + */ + size_t proberesp_len; + + /** + * ssid - The SSID to use in Beacon/Probe Response frames + */ + const u8 *ssid; + + /** + * ssid_len - Length of the SSID (1..32) + */ + size_t ssid_len; + + /** + * hide_ssid - Whether to hide the SSID + */ + enum hide_ssid hide_ssid; + + /** + * pairwise_ciphers - WPA_CIPHER_* bitfield + */ + unsigned int pairwise_ciphers; + + /** + * group_cipher - WPA_CIPHER_* + */ + unsigned int group_cipher; + + /** + * key_mgmt_suites - WPA_KEY_MGMT_* bitfield + */ + unsigned int key_mgmt_suites; + + /** + * auth_algs - WPA_AUTH_ALG_* bitfield + */ + unsigned int auth_algs; + + /** + * wpa_version - WPA_PROTO_* bitfield + */ + unsigned int wpa_version; + + /** + * privacy - Whether privacy is used in the BSS + */ + int privacy; + + /** + * beacon_ies - WPS/P2P IE(s) for Beacon frames + * + * This is used to add IEs like WPS IE and P2P IE by drivers that do + * not use the full Beacon template. + */ + const struct wpabuf *beacon_ies; + + /** + * proberesp_ies - P2P/WPS IE(s) for Probe Response frames + * + * This is used to add IEs like WPS IE and P2P IE by drivers that + * reply to Probe Request frames internally. + */ + const struct wpabuf *proberesp_ies; + + /** + * assocresp_ies - WPS IE(s) for (Re)Association Response frames + * + * This is used to add IEs like WPS IE by drivers that reply to + * (Re)Association Request frames internally. + */ + const struct wpabuf *assocresp_ies; + + /** + * isolate - Whether to isolate frames between associated stations + * + * If this is non-zero, the AP is requested to disable forwarding of + * frames between associated stations. + */ + int isolate; + + /** + * cts_protect - Whether CTS protection is enabled + */ + int cts_protect; + + /** + * preamble - Whether short preamble is enabled + */ + int preamble; + + /** + * short_slot_time - Whether short slot time is enabled + * + * 0 = short slot time disable, 1 = short slot time enabled, -1 = do + * not set (e.g., when 802.11g mode is not in use) + */ + int short_slot_time; + + /** + * ht_opmode - HT operation mode or -1 if HT not in use + */ + int ht_opmode; + + /** + * interworking - Whether Interworking is enabled + */ + int interworking; + + /** + * hessid - Homogeneous ESS identifier or %NULL if not set + */ + const u8 *hessid; + + /** + * access_network_type - Access Network Type (0..15) + * + * This is used for filtering Probe Request frames when Interworking is + * enabled. + */ + u8 access_network_type; +}; + /** * struct wpa_driver_capa - Driver capability information */ @@ -530,7 +723,7 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001 /* Driver needs static WEP key setup after association command */ #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002 -#define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004 +/* unused: 0x00000004 */ /* Driver takes care of RSN 4-way handshake internally; PMK is configured with * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */ #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008 @@ -571,9 +764,24 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000 /* Driver indicates TX status events for EAPOL Data frames */ #define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS 0x00010000 +/* Driver indicates TX status events for Deauth/Disassoc frames */ +#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS 0x00020000 +/* Driver supports roaming (BSS selection) in firmware */ +#define WPA_DRIVER_FLAGS_BSS_SELECTION 0x00040000 +/* Driver supports operating as a TDLS peer */ +#define WPA_DRIVER_FLAGS_TDLS_SUPPORT 0x00080000 +/* Driver requires external TDLS setup/teardown/discovery */ +#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP 0x00100000 +/* Driver indicates support for Probe Response offloading in AP mode */ +#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD 0x00200000 +/* Driver supports U-APSD in AP mode */ +#define WPA_DRIVER_FLAGS_AP_UAPSD 0x00400000 unsigned int flags; int max_scan_ssids; + int max_sched_scan_ssids; + int sched_scan_supported; + int max_match_sets; /** * max_remain_on_chan - Maximum remain-on-channel duration in msec @@ -585,6 +793,20 @@ struct wpa_driver_capa { * supports in AP mode */ unsigned int max_stations; + + /** + * probe_resp_offloads - Bitmap of supported protocols by the driver + * for Probe Response offloading. + */ +/* Driver Probe Response offloading support for WPS ver. 1 */ +#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS 0x00000001 +/* Driver Probe Response offloading support for WPS ver. 2 */ +#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2 0x00000002 +/* Driver Probe Response offloading support for P2P */ +#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P 0x00000004 +/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */ +#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008 + unsigned int probe_resp_offloads; }; @@ -610,6 +832,9 @@ struct hostapd_sta_add_params { size_t supp_rates_len; u16 listen_interval; const struct ieee80211_ht_capabilities *ht_capabilities; + u32 flags; /* bitmask of WPA_STA_* flags */ + int set; /* Set STA parameters instead of add */ + u8 qosinfo; }; struct hostapd_freq_params { @@ -661,6 +886,7 @@ enum wpa_driver_if_type { }; struct wpa_init_params { + void *global_priv; const u8 *bssid; const char *ifname; const u8 *ssid; @@ -693,6 +919,7 @@ struct wpa_bss_params { #define WPA_STA_WMM BIT(1) #define WPA_STA_SHORT_PREAMBLE BIT(2) #define WPA_STA_MFP BIT(3) +#define WPA_STA_TDLS_PEER BIT(4) /** * struct p2p_params - P2P parameters for driver-based P2P management @@ -1079,91 +1306,21 @@ struct wpa_driver_ops { * flags: Variable for returning hardware feature flags * Returns: Pointer to allocated hardware data on success or %NULL on * failure. Caller is responsible for freeing this. - * - * This function is only needed for drivers that export MLME - * (management frame processing) to %wpa_supplicant or hostapd. */ struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv, u16 *num_modes, u16 *flags); /** - * set_channel - Set channel - * @priv: Private driver interface data - * @phymode: HOSTAPD_MODE_IEEE80211B, .. - * @chan: IEEE 802.11 channel number - * @freq: Frequency of the channel in MHz - * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. - */ - int (*set_channel)(void *priv, enum hostapd_hw_mode phymode, int chan, - int freq); - - /** - * set_ssid - Set SSID - * @priv: Private driver interface data - * @ssid: SSID - * @ssid_len: SSID length - * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. - */ - int (*set_ssid)(void *priv, const u8 *ssid, size_t ssid_len); - - /** - * set_bssid - Set BSSID - * @priv: Private driver interface data - * @bssid: BSSID - * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. - */ - int (*set_bssid)(void *priv, const u8 *bssid); - - /** * send_mlme - Send management frame from MLME * @priv: Private driver interface data * @data: IEEE 802.11 management frame with IEEE 802.11 header * @data_len: Size of the management frame + * @noack: Do not wait for this frame to be acked (disable retries) * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. */ - int (*send_mlme)(void *priv, const u8 *data, size_t data_len); - - /** - * mlme_add_sta - Add a STA entry into the driver/netstack - * @priv: Private driver interface data - * @addr: MAC address of the STA (e.g., BSSID of the AP) - * @supp_rates: Supported rate set (from (Re)AssocResp); in IEEE 802.11 - * format (one octet per rate, 1 = 0.5 Mbps) - * @supp_rates_len: Number of entries in supp_rates - * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. When the MLME code - * completes association with an AP, this function is called to - * configure the driver/netstack with a STA entry for data frame - * processing (TX rate control, encryption/decryption). - */ - int (*mlme_add_sta)(void *priv, const u8 *addr, const u8 *supp_rates, - size_t supp_rates_len); - - /** - * mlme_remove_sta - Remove a STA entry from the driver/netstack - * @priv: Private driver interface data - * @addr: MAC address of the STA (e.g., BSSID of the AP) - * Returns: 0 on success, -1 on failure - * - * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. - */ - int (*mlme_remove_sta)(void *priv, const u8 *addr); + int (*send_mlme)(void *priv, const u8 *data, size_t data_len, + int noack); /** * update_ft_ies - Update FT (IEEE 802.11r) IEs @@ -1292,24 +1449,25 @@ struct wpa_driver_ops { struct wpa_driver_auth_params *params); /** - * set_beacon - Set Beacon frame template + * set_ap - Set Beacon and Probe Response information for AP mode * @priv: Private driver interface data - * @head: Beacon head from IEEE 802.11 header to IEs before TIM IE - * @head_len: Length of the head buffer in octets - * @tail: Beacon tail following TIM IE - * @tail_len: Length of the tail buffer in octets - * @dtim_period: DTIM period - * @beacon_int: Beacon interval - * Returns: 0 on success, -1 on failure + * @params: Parameters to use in AP mode * - * This function is used to configure Beacon template for the driver in + * This function is used to configure Beacon template and/or extra IEs + * to add for Beacon and Probe Response frames for the driver in * AP mode. The driver is responsible for building the full Beacon * frame by concatenating the head part with TIM IE generated by the - * driver/firmware and finishing with the tail part. + * driver/firmware and finishing with the tail part. Depending on the + * driver architectue, this can be done either by using the full + * template or the set of additional IEs (e.g., WPS and P2P IE). + * Similarly, Probe Response processing depends on the driver design. + * If the driver (or firmware) takes care of replying to Probe Request + * frames, the extra IEs provided here needs to be added to the Probe + * Response frames. + * + * Returns: 0 on success, -1 on failure */ - int (*set_beacon)(void *priv, const u8 *head, size_t head_len, - const u8 *tail, size_t tail_len, int dtim_period, - int beacon_int); + int (*set_ap)(void *priv, struct wpa_driver_ap_params *params); /** * hapd_init - Initialize driver interface (hostapd only) @@ -1318,7 +1476,7 @@ struct wpa_driver_ops { * Returns: Pointer to private data, %NULL on failure * * This function is used instead of init() or init2() when the driver - * wrapper is used withh hostapd. + * wrapper is used with hostapd. */ void * (*hapd_init)(struct hostapd_data *hapd, struct wpa_init_params *params); @@ -1338,8 +1496,10 @@ struct wpa_driver_ops { * This is an optional function to configure the kernel driver to * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This * can be left undefined (set to %NULL) if IEEE 802.1X support is - * always enabled and the driver uses set_beacon() to set WPA/RSN IE + * always enabled and the driver uses set_ap() to set WPA/RSN IE * for Beacon frames. + * + * DEPRECATED - use set_ap() instead */ int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params); @@ -1351,7 +1511,9 @@ struct wpa_driver_ops { * * This is an optional function to configure privacy field in the * kernel driver for Beacon frames. This can be left undefined (set to - * %NULL) if the driver uses the Beacon template from set_beacon(). + * %NULL) if the driver uses the Beacon template from set_ap(). + * + * DEPRECATED - use set_ap() instead */ int (*set_privacy)(void *priv, int enabled); @@ -1393,7 +1555,9 @@ struct wpa_driver_ops { * This is an optional function to add information elements in the * kernel driver for Beacon and Probe Response frames. This can be left * undefined (set to %NULL) if the driver uses the Beacon template from - * set_beacon(). + * set_ap(). + * + * DEPRECATED - use set_ap() instead */ int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len); @@ -1467,8 +1631,7 @@ struct wpa_driver_ops { * Returns: Length of the SSID on success, -1 on failure * * This function need not be implemented if the driver uses Beacon - * template from set_beacon() and does not reply to Probe Request - * frames. + * template from set_ap() and does not reply to Probe Request frames. */ int (*hapd_get_ssid)(void *priv, u8 *buf, int len); @@ -1478,6 +1641,8 @@ struct wpa_driver_ops { * @buf: SSID * @len: Length of the SSID in octets * Returns: 0 on success, -1 on failure + * + * DEPRECATED - use set_ap() instead */ int (*hapd_set_ssid)(void *priv, const u8 *buf, int len); @@ -1501,6 +1666,9 @@ struct wpa_driver_ops { * 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 * does not take care of association processing. + * + * With TDLS, this function is also used to add or set (params->set 1) + * TDLS peer entries. */ int (*sta_add)(void *priv, struct hostapd_sta_add_params *params); @@ -1557,41 +1725,6 @@ struct wpa_driver_ops { int total_flags, int flags_or, int flags_and); /** - * set_rate_sets - Set supported and basic rate sets (AP only) - * @priv: Private driver interface data - * @supp_rates: -1 terminated array of supported rates in 100 kbps - * @basic_rates: -1 terminated array of basic rates in 100 kbps - * @mode: hardware mode (HOSTAPD_MODE_*) - * Returns: 0 on success, -1 on failure - */ - int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates, - int mode); - - /** - * set_cts_protect - Set CTS protection mode (AP only) - * @priv: Private driver interface data - * @value: Whether CTS protection is enabled - * Returns: 0 on success, -1 on failure - */ - int (*set_cts_protect)(void *priv, int value); - - /** - * set_preamble - Set preamble mode (AP only) - * @priv: Private driver interface data - * @value: Whether short preamble is enabled - * Returns: 0 on success, -1 on failure - */ - int (*set_preamble)(void *priv, int value); - - /** - * set_short_slot_time - Set short slot time (AP only) - * @priv: Private driver interface data - * @value: Whether short slot time is enabled - * Returns: 0 on success, -1 on failure - */ - int (*set_short_slot_time)(void *priv, int value); - - /** * set_tx_queue_params - Set TX queue parameters * @priv: Private driver interface data * @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK) @@ -1604,17 +1737,6 @@ struct wpa_driver_ops { int cw_max, int burst_time); /** - * valid_bss_mask - Validate BSSID mask - * @priv: Private driver interface data - * @addr: Address - * @mask: Mask - * Returns: 0 if mask is valid, -1 if mask is not valid, 1 if mask can - * be used, but the main interface address must be the first address in - * the block if mask is applied - */ - int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask); - - /** * if_add - Add a virtual interface * @priv: Private driver interface data * @type: Interface type @@ -1709,19 +1831,6 @@ struct wpa_driver_ops { int (*set_radius_acl_expire)(void *priv, const u8 *mac); /** - * set_ht_params - Set HT parameters (AP only) - * @priv: Private driver interface data - * @ht_capab: HT Capabilities IE - * @ht_capab_len: Length of ht_capab in octets - * @ht_oper: HT Operation IE - * @ht_oper_len: Length of ht_oper in octets - * Returns: 0 on success, -1 on failure - */ - int (*set_ht_params)(void *priv, - const u8 *ht_capab, size_t ht_capab_len, - const u8 *ht_oper, size_t ht_oper_len); - - /** * set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP) * @priv: Private driver interface data * @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s) @@ -1733,7 +1842,7 @@ struct wpa_driver_ops { * * This is an optional function to add WPS IE in the kernel driver for * Beacon and Probe Response frames. This can be left undefined (set - * to %NULL) if the driver uses the Beacon template from set_beacon() + * to %NULL) if the driver uses the Beacon template from set_ap() * and does not process Probe Request frames. If the driver takes care * of (Re)Association frame processing, the assocresp buffer includes * WPS IE(s) that need to be added to (Re)Association Response frames @@ -1746,6 +1855,8 @@ struct wpa_driver_ops { * also used to provide Probe Response IEs for P2P Listen state * operations for drivers that generate the Probe Response frames * internally. + * + * DEPRECATED - use set_ap() instead */ int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon, const struct wpabuf *proberesp, @@ -1782,6 +1893,7 @@ struct wpa_driver_ops { * @bssid: BSSID (Address 3) * @data: Frame body * @data_len: data length in octets + @ @no_cck: Whether CCK rates must not be used to transmit this frame * Returns: 0 on success, -1 on failure * * This command can be used to request the driver to transmit an action @@ -1799,7 +1911,7 @@ struct wpa_driver_ops { */ int (*send_action)(void *priv, unsigned int freq, unsigned int wait, const u8 *dst, const u8 *src, const u8 *bssid, - const u8 *data, size_t data_len); + const u8 *data, size_t data_len, int no_cck); /** * send_action_cancel_wait - Cancel action frame TX wait @@ -1866,19 +1978,6 @@ struct wpa_driver_ops { int (*probe_req_report)(void *priv, int report); /** - * disable_11b_rates - Set whether IEEE 802.11b rates are used for TX - * @priv: Private driver interface data - * @disabled: Whether IEEE 802.11b rates are disabled - * Returns: 0 on success, -1 on failure (or if not supported) - * - * This command is used to disable IEEE 802.11b rates (1, 2, 5.5, and - * 11 Mbps) as TX rates for data and management frames. This can be - * used to optimize channel use when there is no need to support IEEE - * 802.11b-only devices. - */ - int (*disable_11b_rates)(void *priv, int disabled); - - /** * deinit_ap - Deinitialize AP mode * @priv: Private driver interface data * Returns: 0 on success, -1 on failure (or if not supported) @@ -1990,11 +2089,6 @@ struct wpa_driver_ops { int (*ampdu)(void *priv, int ampdu); /** - * set_intra_bss - Enables/Disables intra BSS bridging - */ - int (*set_intra_bss)(void *priv, int enabled); - - /** * get_radio_name - Get physical radio name for the device * @priv: Private driver interface data * Returns: Radio name or %NULL if not known @@ -2132,7 +2226,7 @@ struct wpa_driver_ops { * struct wpa_driver_capa. */ int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr, - u16 config_methods); + u16 config_methods, int join); /** * p2p_sd_request - Schedule a service discovery query @@ -2232,7 +2326,7 @@ struct wpa_driver_ops { * @status_code: Status Code or Reason Code to use (if needed) * @buf: TDLS IEs to add to the message * @len: Length of buf in octets - * Returns: 0 on success, -1 on failure + * Returns: 0 on success, negative (<0) on failure * * This optional function can be used to send packet to driver which is * responsible for receiving and sending all TDLS packets. @@ -2241,6 +2335,16 @@ struct wpa_driver_ops { u8 dialog_token, u16 status_code, const u8 *buf, size_t len); + /** + * tdls_oper - Ask the driver to perform high-level TDLS operations + * @priv: Private driver interface data + * @oper: TDLS high-level operation. See %enum tdls_oper + * @peer: Destination (peer) MAC address + * Returns: 0 on success, negative (<0) on failure + * + * This optional function can be used to send high-level TDLS commands + * to the driver. + */ int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer); /** @@ -2259,9 +2363,11 @@ struct wpa_driver_ops { * This function can be used to set authentication algorithms for AP * mode when static WEP is used. If the driver uses user space MLME/SME * implementation, there is no need to implement this function. + * + * DEPRECATED - use set_ap() instead */ int (*set_authmode)(void *priv, int authmode); - +#ifdef ANDROID /** * driver_cmd - execute driver-specific command * @priv: private driver interface data @@ -2272,6 +2378,135 @@ struct wpa_driver_ops { * Returns: 0 on success, -1 on failure */ int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len); +#endif + /** + * set_rekey_info - Set rekey information + * @priv: Private driver interface data + * @kek: Current KEK + * @kck: Current KCK + * @replay_ctr: Current EAPOL-Key Replay Counter + * + * This optional function can be used to provide information for the + * driver/firmware to process EAPOL-Key frames in Group Key Handshake + * while the host (including wpa_supplicant) is sleeping. + */ + void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck, + const u8 *replay_ctr); + + /** + * sta_assoc - Station association indication + * @priv: Private driver interface data + * @own_addr: Source address and BSSID for association frame + * @addr: MAC address of the station to associate + * @reassoc: flag to indicate re-association + * @status: association response status code + * @ie: assoc response ie buffer + * @len: ie buffer length + * Returns: 0 on success, -1 on failure + * + * This function indicates the driver to send (Re)Association + * Response frame to the station. + */ + int (*sta_assoc)(void *priv, const u8 *own_addr, const u8 *addr, + int reassoc, u16 status, const u8 *ie, size_t len); + + /** + * sta_auth - Station authentication indication + * @priv: Private driver interface data + * @own_addr: Source address and BSSID for authentication frame + * @addr: MAC address of the station to associate + * @seq: authentication sequence number + * @status: authentication response status code + * @ie: authentication frame ie buffer + * @len: ie buffer length + * + * This function indicates the driver to send Authentication frame + * to the station. + */ + int (*sta_auth)(void *priv, const u8 *own_addr, const u8 *addr, + u16 seq, u16 status, const u8 *ie, size_t len); + + /** + * add_tspec - Add traffic stream + * @priv: Private driver interface data + * @addr: MAC address of the station to associate + * @tspec_ie: tspec ie buffer + * @tspec_ielen: tspec ie length + * Returns: 0 on success, -1 on failure + * + * This function adds the traffic steam for the station + * and fills the medium_time in tspec_ie. + */ + int (*add_tspec)(void *priv, const u8 *addr, u8 *tspec_ie, + size_t tspec_ielen); + + /** + * add_sta_node - Add a station node in the driver + * @priv: Private driver interface data + * @addr: MAC address of the station to add + * @auth_alg: authentication algorithm used by the station + * Returns: 0 on success, -1 on failure + * + * This function adds the station node in the driver, when + * the station gets added by FT-over-DS. + */ + int (*add_sta_node)(void *priv, const u8 *addr, u16 auth_alg); + + /** + * 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 + * the hardware. Every time scan results are available, the + * driver should report scan results event for wpa_supplicant + * which will eventually request the results with + * wpa_driver_get_scan_results2(). This operation is optional + * 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); + + /** + * stop_sched_scan - Request the driver to stop a scheduled scan + * @priv: Private driver interface data + * Returns: 0 on success, -1 on failure + * + * This should cause the scheduled scan to be stopped and + * results should stop being sent. Must be supported if + * sched_scan is supported. + */ + int (*stop_sched_scan)(void *priv); + + /** + * poll_client - Probe (null data or such) the given station + * @priv: Private driver interface data + * @own_addr: MAC address of sending interface + * @addr: MAC address of the station to probe + * @qos: Indicates whether station is QoS station + * + * This function is used to verify whether an associated station is + * still present. This function does not need to be implemented if the + * driver provides such inactivity polling mechanism. + */ + void (*poll_client)(void *priv, const u8 *own_addr, + const u8 *addr, int qos); +#ifdef ANDROID_P2P + /** + * go_switch_channel - Announce channel switch and migrate the GO to a + * given frequency. + * @priv: Private driver interface data + * @freq: frequency in MHz + * Returns: 0 on success, -1 on failure + * + * This function is used to move the GO to the legacy STA channel to avoid + * frequency conflict in single channel concurrency. + */ + int (*go_switch_channel)(void *priv, unsigned int freq); +#endif }; @@ -2674,7 +2909,35 @@ enum wpa_event_type { /** * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore */ - EVENT_IBSS_PEER_LOST + EVENT_IBSS_PEER_LOST, + + /** + * EVENT_DRIVER_GTK_REKEY - Device/driver did GTK rekey + * + * This event carries the new replay counter to notify wpa_supplicant + * of the current EAPOL-Key Replay Counter in case the driver/firmware + * completed Group Key Handshake while the host (including + * wpa_supplicant was sleeping). + */ + EVENT_DRIVER_GTK_REKEY, + + /** + * EVENT_SCHED_SCAN_STOPPED - Scheduled scan was stopped + */ + EVENT_SCHED_SCAN_STOPPED, + + /** + * EVENT_DRIVER_CLIENT_POLL_OK - Station responded to poll + * + * This event indicates that the station responded to the poll + * initiated with @poll_client. + */ + EVENT_DRIVER_CLIENT_POLL_OK, + + /** + * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status + */ + EVENT_EAPOL_TX_STATUS }; @@ -2898,7 +3161,9 @@ union wpa_event_data { */ struct auth_info { u8 peer[ETH_ALEN]; + u8 bssid[ETH_ALEN]; u16 auth_type; + u16 auth_transaction; u16 status_code; const u8 *ies; size_t ies_len; @@ -2966,8 +3231,9 @@ union wpa_event_data { * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events */ struct rx_from_unknown { - const u8 *frame; - size_t len; + const u8 *bssid; + const u8 *addr; + int wds; } rx_from_unknown; /** @@ -3075,6 +3341,18 @@ union wpa_event_data { const u8 *sa; /** + * da - Destination address of the received Probe Request frame + * or %NULL if not available + */ + const u8 *da; + + /** + * bssid - BSSID of the received Probe Request frame or %NULL + * if not available + */ + const u8 *bssid; + + /** * ie - IEs from the Probe Request body */ const u8 *ie; @@ -3206,6 +3484,39 @@ union wpa_event_data { struct ibss_peer_lost { u8 peer[ETH_ALEN]; } ibss_peer_lost; + + /** + * struct driver_gtk_rekey - Data for EVENT_DRIVER_GTK_REKEY + */ + struct driver_gtk_rekey { + const u8 *bssid; + const u8 *replay_ctr; + } driver_gtk_rekey; + + /** + * struct client_poll - Data for EVENT_DRIVER_CLIENT_POLL_OK events + * @addr: station address + */ + struct client_poll { + u8 addr[ETH_ALEN]; + } client_poll; + + /** + * struct eapol_tx_status + * @dst: Original destination + * @data: Data starting with IEEE 802.1X header (!) + * @data_len: Length of data + * @ack: Indicates ack or lost frame + * + * This corresponds to hapd_send_eapol if the frame sent + * there isn't just reported as EVENT_TX_STATUS. + */ + struct eapol_tx_status { + const u8 *dst; + const u8 *data; + int data_len; + int ack; + } eapol_tx_status; }; /** @@ -3258,4 +3569,10 @@ static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data, wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event); } +/* driver_common.c */ +void wpa_scan_results_free(struct wpa_scan_results *res); + +/* Convert wpa_event_type to a string for logging */ +const char * event_to_string(enum wpa_event_type event); + #endif /* DRIVER_H */ diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index 1e78f6e..b17d1a6 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -34,7 +34,7 @@ */ #define ATH_WPS_IE -#include "os/linux/include/ieee80211_external.h" +#include "ieee80211_external.h" #ifdef CONFIG_WPS @@ -45,7 +45,7 @@ #endif #endif /* CONFIG_WPS */ -#include "wireless_copy.h" +#include "linux_wext.h" #include "driver.h" #include "eloop.h" @@ -641,6 +641,7 @@ atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, (unsigned long) ie_len); + wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len); wpabuf_free(drv->wpa_ie); drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len); @@ -658,6 +659,8 @@ atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) wpabuf_len(drv->wps_beacon_ie)); app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie); } + wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)", + app_ie->app_buf, app_ie->app_buflen); set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, sizeof(struct ieee80211req_getset_appiebuf) + app_ie->app_buflen); @@ -672,6 +675,8 @@ atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) wpabuf_len(drv->wps_probe_resp_ie); } else app_ie->app_buflen = ie_len; + wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)", + app_ie->app_buf, app_ie->app_buflen); set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, sizeof(struct ieee80211req_getset_appiebuf) + app_ie->app_buflen); @@ -748,6 +753,8 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, os_memset(&event, 0, sizeof(event)); event.rx_probe_req.sa = mgmt->sa; + event.rx_probe_req.da = mgmt->da; + event.rx_probe_req.bssid = mgmt->bssid; event.rx_probe_req.ie = mgmt->u.probe_req.variable; event.rx_probe_req.ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); @@ -785,8 +792,9 @@ atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) u8 buf[512]; struct ieee80211req_getset_appiebuf *beac_ie; - wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, - (unsigned long) len); + wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__, + (unsigned long) len, frametype); + wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len); beac_ie = (struct ieee80211req_getset_appiebuf *) buf; beac_ie->app_frmtype = frametype; @@ -797,11 +805,15 @@ atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) if (((frametype == IEEE80211_APPIE_FRAME_BEACON) || (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) && (drv->wpa_ie != NULL)) { + wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE", + drv->wpa_ie); os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie), wpabuf_len(drv->wpa_ie)); beac_ie->app_buflen += wpabuf_len(drv->wpa_ie); } + wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF", + beac_ie->app_buf, beac_ie->app_buflen); return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, sizeof(struct ieee80211req_getset_appiebuf) + beac_ie->app_buflen); @@ -814,6 +826,11 @@ atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, { struct atheros_driver_data *drv = priv; + wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon); + wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp", + proberesp); + wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp", + assocresp); wpabuf_free(drv->wps_beacon_ie); drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL; wpabuf_free(drv->wps_probe_resp_ie); @@ -1332,6 +1349,8 @@ atheros_get_ssid(void *priv, u8 *buf, int len) os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.essid.pointer = (caddr_t) buf; iwr.u.essid.length = len; + iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ? + IW_ESSID_MAX_SIZE : len; if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { perror("ioctl[SIOCGIWESSID]"); @@ -1374,6 +1393,34 @@ static int atheros_set_authmode(void *priv, int auth_algs) return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode); } +static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params) +{ + /* + * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x, + * set_generic_elem, and hapd_set_ssid. + */ + + wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x " + "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x " + "wpa_version=0x%x privacy=%d interworking=%d", + params->pairwise_ciphers, params->group_cipher, + params->key_mgmt_suites, params->auth_algs, + params->wpa_version, params->privacy, params->interworking); + wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID", + params->ssid, params->ssid_len); + if (params->hessid) + wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR, + MAC2STR(params->hessid)); + wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies", + params->beacon_ies); + wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies", + params->proberesp_ies); + wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies", + params->assocresp_ies); + + return 0; +} + const struct wpa_driver_ops wpa_driver_atheros_ops = { .name = "atheros", .hapd_init = atheros_init, @@ -1396,4 +1443,5 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = { .commit = atheros_commit, .set_ap_wps_ie = atheros_set_ap_wps_ie, .set_authmode = atheros_set_authmode, + .set_ap = atheros_set_ap, }; diff --git a/src/drivers/driver_broadcom.c b/src/drivers/driver_broadcom.c deleted file mode 100644 index cb88543..0000000 --- a/src/drivers/driver_broadcom.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - * WPA Supplicant - driver interaction with old Broadcom wl.o driver - * Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru> - * Copyright (c) 2004, Jouni Malinen <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - * - * Please note that the newer Broadcom driver ("hybrid Linux driver") supports - * Linux wireless extensions and does not need (or even work) with this old - * driver wrapper. Use driver_wext.c with that driver. - */ - -#include "includes.h" - -#include <sys/ioctl.h> - -#include "common.h" - -#if 0 -#include <netpacket/packet.h> -#include <net/ethernet.h> /* the L2 protocols */ -#else -#include <linux/if_packet.h> -#include <linux/if_ether.h> /* The L2 protocols */ -#endif -#include <net/if.h> -#include <typedefs.h> - -/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys - * WRT54G GPL tarball. */ -#include <wlioctl.h> - -#include "driver.h" -#include "eloop.h" - -struct wpa_driver_broadcom_data { - void *ctx; - int ioctl_sock; - int event_sock; - char ifname[IFNAMSIZ + 1]; -}; - - -#ifndef WLC_DEAUTHENTICATE -#define WLC_DEAUTHENTICATE 143 -#endif -#ifndef WLC_DEAUTHENTICATE_WITH_REASON -#define WLC_DEAUTHENTICATE_WITH_REASON 201 -#endif -#ifndef WLC_SET_TKIP_COUNTERMEASURES -#define WLC_SET_TKIP_COUNTERMEASURES 202 -#endif - -#if !defined(PSK_ENABLED) /* NEW driver interface */ -#define WL_VERSION 360130 -/* wireless authentication bit vector */ -#define WPA_ENABLED 1 -#define PSK_ENABLED 2 - -#define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED) -#define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED) -#define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED)) - -#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY - -typedef wl_wsec_key_t wsec_key_t; -#endif - -typedef struct { - uint32 val; - struct ether_addr ea; - uint16 res; -} wlc_deauth_t; - - -static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx, - void *timeout_ctx); - -static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd, - void *buf, int len) -{ - struct ifreq ifr; - wl_ioctl_t ioc; - int ret = 0; - - wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)", - drv->ifname, cmd, len, buf); - /* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */ - - ioc.cmd = cmd; - ioc.buf = buf; - ioc.len = len; - os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ); - ifr.ifr_data = (caddr_t) &ioc; - if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) { - if (cmd != WLC_GET_MAGIC) - perror(ifr.ifr_name); - wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d", - cmd, ret); - } - - return ret; -} - -static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid) -{ - struct wpa_driver_broadcom_data *drv = priv; - if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0) - return 0; - - os_memset(bssid, 0, ETH_ALEN); - return -1; -} - -static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid) -{ - struct wpa_driver_broadcom_data *drv = priv; - wlc_ssid_t s; - - if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1) - return -1; - - os_memcpy(ssid, s.SSID, s.SSID_len); - return s.SSID_len; -} - -static int wpa_driver_broadcom_set_wpa(void *priv, int enable) -{ - struct wpa_driver_broadcom_data *drv = priv; - unsigned int wauth, wsec; - struct ether_addr ea; - - os_memset(&ea, enable ? 0xff : 0, sizeof(ea)); - if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) == - -1 || - broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1) - return -1; - - if (enable) { - wauth = PSK_ENABLED; - wsec = TKIP_ENABLED; - } else { - wauth = 255; - wsec &= ~(TKIP_ENABLED | AES_ENABLED); - } - - if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) == - -1 || - broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1) - return -1; - - /* FIX: magic number / error handling? */ - broadcom_ioctl(drv, 122, &ea, sizeof(ea)); - - return 0; -} - -static int wpa_driver_broadcom_set_key(const char *ifname, void *priv, - enum wpa_alg alg, - const u8 *addr, int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) -{ - struct wpa_driver_broadcom_data *drv = priv; - int ret; - wsec_key_t wkt; - - os_memset(&wkt, 0, sizeof wkt); - wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d", - set_tx ? "PRIMARY " : "", key_idx, alg); - if (key && key_len > 0) - wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len); - - switch (alg) { - case WPA_ALG_NONE: - wkt.algo = CRYPTO_ALGO_OFF; - break; - case WPA_ALG_WEP: - wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */ - break; - case WPA_ALG_TKIP: - wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */ - break; - case WPA_ALG_CCMP: - wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM; - * AES_OCB_MSDU, AES_OCB_MPDU? */ - break; - default: - wkt.algo = CRYPTO_ALGO_NALG; - break; - } - - if (seq && seq_len > 0) - wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len); - - if (addr) - wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN); - - wkt.index = key_idx; - wkt.len = key_len; - if (key && key_len > 0) { - os_memcpy(wkt.data, key, key_len); - if (key_len == 32) { - /* hack hack hack XXX */ - os_memcpy(&wkt.data[16], &key[24], 8); - os_memcpy(&wkt.data[24], &key[16], 8); - } - } - /* wkt.algo = CRYPTO_ALGO_...; */ - wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY; - if (addr && set_tx) - os_memcpy(&wkt.ea, addr, sizeof(wkt.ea)); - ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt)); - if (addr && set_tx) { - /* FIX: magic number / error handling? */ - broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea)); - } - return ret; -} - - -static void wpa_driver_broadcom_event_receive(int sock, void *ctx, - void *sock_ctx) -{ - char buf[8192]; - int left; - wl_wpa_header_t *wwh; - union wpa_event_data data; - u8 *resp_ies = NULL; - - if ((left = recv(sock, buf, sizeof buf, 0)) < 0) - return; - - wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left); - - if ((size_t) left < sizeof(wl_wpa_header_t)) - return; - - wwh = (wl_wpa_header_t *) buf; - - if (wwh->snap.type != WL_WPA_ETHER_TYPE) - return; - if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0) - return; - - os_memset(&data, 0, sizeof(data)); - - switch (wwh->type) { - case WLC_ASSOC_MSG: - left -= WL_WPA_HEADER_LEN; - wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)", - left); - if (left > 0) { - resp_ies = os_malloc(left); - if (resp_ies == NULL) - return; - os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left); - data.assoc_info.resp_ies = resp_ies; - data.assoc_info.resp_ies_len = left; - } - - wpa_supplicant_event(ctx, EVENT_ASSOC, &data); - os_free(resp_ies); - break; - case WLC_DISASSOC_MSG: - wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE"); - wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); - break; - case WLC_PTK_MIC_MSG: - wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE"); - data.michael_mic_failure.unicast = 1; - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); - break; - case WLC_GTK_MIC_MSG: - wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE"); - data.michael_mic_failure.unicast = 0; - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); - break; - default: - wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)", - wwh->type); - break; - } -} - -static void * wpa_driver_broadcom_init(void *ctx, const char *ifname) -{ - int s; - struct sockaddr_ll ll; - struct wpa_driver_broadcom_data *drv; - struct ifreq ifr; - - /* open socket to kernel */ - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - perror("socket"); - return NULL; - } - /* do it */ - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { - perror(ifr.ifr_name); - return NULL; - } - - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->ctx = ctx; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - drv->ioctl_sock = s; - - s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2)); - if (s < 0) { - perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))"); - close(drv->ioctl_sock); - os_free(drv); - return NULL; - } - - os_memset(&ll, 0, sizeof(ll)); - ll.sll_family = AF_PACKET; - ll.sll_protocol = ntohs(ETH_P_802_2); - ll.sll_ifindex = ifr.ifr_ifindex; - ll.sll_hatype = 0; - ll.sll_pkttype = PACKET_HOST; - ll.sll_halen = 0; - - if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) { - perror("bind(netlink)"); - close(s); - close(drv->ioctl_sock); - os_free(drv); - return NULL; - } - - eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx, - NULL); - drv->event_sock = s; - wpa_driver_broadcom_set_wpa(drv, 1); - - return drv; -} - -static void wpa_driver_broadcom_deinit(void *priv) -{ - struct wpa_driver_broadcom_data *drv = priv; - wpa_driver_broadcom_set_wpa(drv, 0); - eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx); - eloop_unregister_read_sock(drv->event_sock); - close(drv->event_sock); - close(drv->ioctl_sock); - os_free(drv); -} - -static int wpa_driver_broadcom_set_countermeasures(void *priv, - int enabled) -{ -#if 0 - struct wpa_driver_broadcom_data *drv = priv; - /* FIX: ? */ - return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled, - sizeof(enabled)); -#else - return 0; -#endif -} - -static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled) -{ - struct wpa_driver_broadcom_data *drv = priv; - /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */ - int _restrict = (enabled ? 1 : 0); - - if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT, - &_restrict, sizeof(_restrict)) < 0 || - broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT, - &_restrict, sizeof(_restrict)) < 0) - return -1; - - return 0; -} - -static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx, - void *timeout_ctx) -{ - wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); - wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -} - -static int wpa_driver_broadcom_scan(void *priv, - struct wpa_driver_scan_params *params) -{ - struct wpa_driver_broadcom_data *drv = priv; - wlc_ssid_t wst = { 0, "" }; - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - - if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) { - wst.SSID_len = ssid_len; - os_memcpy(wst.SSID, ssid, ssid_len); - } - - if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0) - return -1; - - eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx); - eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv, - drv->ctx); - return 0; -} - - -static const int frequency_list[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 -}; - -struct bss_ie_hdr { - u8 elem_id; - u8 len; - u8 oui[3]; - /* u8 oui_type; */ - /* u16 version; */ -} __attribute__ ((packed)); - -static struct wpa_scan_results * -wpa_driver_broadcom_get_scan_results(void *priv) -{ - struct wpa_driver_broadcom_data *drv = priv; - char *buf; - wl_scan_results_t *wsr; - wl_bss_info_t *wbi; - size_t ap_num; - struct wpa_scan_results *res; - - buf = os_malloc(WLC_IOCTL_MAXLEN); - if (buf == NULL) - return NULL; - - wsr = (wl_scan_results_t *) buf; - - wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr); - wsr->version = 107; - wsr->count = 0; - - if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) { - os_free(buf); - return NULL; - } - - res = os_zalloc(sizeof(*res)); - if (res == NULL) { - os_free(buf); - return NULL; - } - - res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *)); - if (res->res == NULL) { - os_free(res); - os_free(buf); - return NULL; - } - - for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) { - struct wpa_scan_res *r; - r = os_malloc(sizeof(*r) + wbi->ie_length); - if (r == NULL) - break; - res->res[res->num++] = r; - - os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN); - r->freq = frequency_list[wbi->channel - 1]; - /* get ie's */ - os_memcpy(r + 1, wbi + 1, wbi->ie_length); - r->ie_len = wbi->ie_length; - - wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length); - } - - wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu " - "BSSes)", - wsr->buflen, (unsigned long) ap_num); - - os_free(buf); - return res; - } - -static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr, - int reason_code) -{ - struct wpa_driver_broadcom_data *drv = priv; - wlc_deauth_t wdt; - wdt.val = reason_code; - os_memcpy(&wdt.ea, addr, sizeof wdt.ea); - wdt.res = 0x7fff; - return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt, - sizeof(wdt)); -} - -static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr, - int reason_code) -{ - struct wpa_driver_broadcom_data *drv = priv; - return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0); -} - -static int -wpa_driver_broadcom_associate(void *priv, - struct wpa_driver_associate_params *params) -{ - struct wpa_driver_broadcom_data *drv = priv; - wlc_ssid_t s; - int infra = 1; - int auth = 0; - int wsec = 4; - int dummy; - int wpa_auth; - int ret; - - ret = wpa_driver_broadcom_set_drop_unencrypted( - drv, params->drop_unencrypted); - - s.SSID_len = params->ssid_len; - os_memcpy(s.SSID, params->ssid, params->ssid_len); - - switch (params->pairwise_suite) { - case CIPHER_WEP40: - case CIPHER_WEP104: - wsec = 1; - break; - - case CIPHER_TKIP: - wsec = 2; - break; - - case CIPHER_CCMP: - wsec = 4; - break; - - default: - wsec = 0; - break; - } - - switch (params->key_mgmt_suite) { - case KEY_MGMT_802_1X: - wpa_auth = 1; - break; - - case KEY_MGMT_PSK: - wpa_auth = 2; - break; - - default: - wpa_auth = 255; - break; - } - - /* printf("broadcom_associate: %u %u %u\n", pairwise_suite, - * group_suite, key_mgmt_suite); - * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec)); - * wl join uses wlc_sec_wep here, not wlc_set_wsec */ - - if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 || - broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth, - sizeof(wpa_auth)) < 0 || - broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 || - broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 || - broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 || - broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 || - broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0) - return -1; - - return ret; -} - -const struct wpa_driver_ops wpa_driver_broadcom_ops = { - .name = "broadcom", - .desc = "Broadcom wl.o driver", - .get_bssid = wpa_driver_broadcom_get_bssid, - .get_ssid = wpa_driver_broadcom_get_ssid, - .set_key = wpa_driver_broadcom_set_key, - .init = wpa_driver_broadcom_init, - .deinit = wpa_driver_broadcom_deinit, - .set_countermeasures = wpa_driver_broadcom_set_countermeasures, - .scan2 = wpa_driver_broadcom_scan, - .get_scan_results2 = wpa_driver_broadcom_get_scan_results, - .deauthenticate = wpa_driver_broadcom_deauthenticate, - .disassociate = wpa_driver_broadcom_disassociate, - .associate = wpa_driver_broadcom_associate, -}; diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c new file mode 100644 index 0000000..26ca8d6 --- /dev/null +++ b/src/drivers/driver_common.c @@ -0,0 +1,90 @@ +/* + * Common driver-related functions + * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" +#include "utils/common.h" +#include "driver.h" + +void wpa_scan_results_free(struct wpa_scan_results *res) +{ + size_t i; + + if (res == NULL) + return; + + for (i = 0; i < res->num; i++) + os_free(res->res[i]); + os_free(res->res); + os_free(res); +} + + +const char * event_to_string(enum wpa_event_type event) +{ +#define E2S(n) case EVENT_ ## n: return #n + switch (event) { + E2S(ASSOC); + E2S(DISASSOC); + E2S(MICHAEL_MIC_FAILURE); + E2S(SCAN_RESULTS); + E2S(ASSOCINFO); + E2S(INTERFACE_STATUS); + E2S(PMKID_CANDIDATE); + E2S(STKSTART); + E2S(TDLS); + E2S(FT_RESPONSE); + E2S(IBSS_RSN_START); + E2S(AUTH); + E2S(DEAUTH); + E2S(ASSOC_REJECT); + E2S(AUTH_TIMED_OUT); + E2S(ASSOC_TIMED_OUT); + E2S(FT_RRB_RX); + E2S(WPS_BUTTON_PUSHED); + E2S(TX_STATUS); + E2S(RX_FROM_UNKNOWN); + E2S(RX_MGMT); + E2S(RX_ACTION); + E2S(REMAIN_ON_CHANNEL); + E2S(CANCEL_REMAIN_ON_CHANNEL); + E2S(MLME_RX); + E2S(RX_PROBE_REQ); + E2S(NEW_STA); + E2S(EAPOL_RX); + E2S(SIGNAL_CHANGE); + E2S(INTERFACE_ENABLED); + E2S(INTERFACE_DISABLED); + E2S(CHANNEL_LIST_CHANGED); + E2S(INTERFACE_UNAVAILABLE); + E2S(BEST_CHANNEL); + E2S(UNPROT_DEAUTH); + E2S(UNPROT_DISASSOC); + E2S(STATION_LOW_ACK); + E2S(P2P_DEV_FOUND); + E2S(P2P_GO_NEG_REQ_RX); + E2S(P2P_GO_NEG_COMPLETED); + E2S(P2P_PROV_DISC_REQUEST); + E2S(P2P_PROV_DISC_RESPONSE); + E2S(P2P_SD_REQUEST); + E2S(P2P_SD_RESPONSE); + E2S(IBSS_PEER_LOST); + E2S(DRIVER_GTK_REKEY); + E2S(SCHED_SCAN_STOPPED); + E2S(DRIVER_CLIENT_POLL_OK); + E2S(EAPOL_TX_STATUS); + } + + return "UNKNOWN"; +#undef E2S +} diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c index e855c1b..8fc0efd 100644 --- a/src/drivers/driver_hostap.c +++ b/src/drivers/driver_hostap.c @@ -15,7 +15,7 @@ #include "includes.h" #include <sys/ioctl.h> -#include "wireless_copy.h" +#include "linux_wext.h" #include "common.h" #include "driver.h" #include "driver_wext.h" @@ -23,8 +23,6 @@ #include "driver_hostap.h" -#ifdef HOSTAPD - #include <net/if_arp.h> #include <netpacket/packet.h> @@ -32,6 +30,7 @@ #include "netlink.h" #include "linux_ioctl.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" /* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X @@ -84,8 +83,8 @@ static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len, sa = hdr->addr2; os_memset(&event, 0, sizeof(event)); - event.rx_from_unknown.frame = buf; - event.rx_from_unknown.len = len; + event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len); + event.rx_from_unknown.addr = sa; wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event); pos = (u8 *) (hdr + 1); @@ -148,7 +147,6 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len) { struct ieee80211_hdr *hdr; u16 fc, extra_len, type, stype; - unsigned char *extra = NULL; size_t data_len = len; int ver; union wpa_event_data event; @@ -185,7 +183,6 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len) return; } len -= extra_len + 2; - extra = buf + len; } else if (ver == 1 || ver == 2) { handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0); return; @@ -273,7 +270,7 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr) } -static int hostap_send_mlme(void *priv, const u8 *msg, size_t len) +static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack) { struct hostap_driver_data *drv = priv; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg; @@ -322,7 +319,7 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, pos += 2; memcpy(pos, data, data_len); - res = hostap_send_mlme(drv, (u8 *) hdr, len); + res = hostap_send_mlme(drv, (u8 *) hdr, len, 0); if (res < 0) { wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - " "failed: %d (%s)", @@ -1054,7 +1051,26 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.deauth.reason_code = host_to_le16(reason); return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth)); + sizeof(mgmt.u.deauth), 0); +} + + +static int hostap_set_freq(void *priv, struct hostapd_freq_params *freq) +{ + struct hostap_driver_data *drv = priv; + struct iwreq iwr; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.freq.m = freq->channel; + iwr.u.freq.e = 0; + + if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { + perror("ioctl[SIOCSIWFREQ]"); + return -1; + } + + return 0; } @@ -1072,7 +1088,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.disassoc.reason_code = host_to_le16(reason); return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc)); + sizeof(mgmt.u.disassoc), 0); } @@ -1126,492 +1142,38 @@ static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv, return mode; } -#else /* HOSTAPD */ - -struct wpa_driver_hostap_data { - void *wext; /* private data for driver_wext */ - void *ctx; - char ifname[IFNAMSIZ + 1]; - int sock; - int current_mode; /* infra/adhoc */ -}; - - -static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg); - - -static int hostapd_ioctl(struct wpa_driver_hostap_data *drv, - struct prism2_hostapd_param *param, - int len, int show_err) -{ - struct iwreq iwr; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) param; - iwr.u.data.length = len; - - if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) { - int ret = errno; - if (show_err) - perror("ioctl[PRISM2_IOCTL_HOSTAPD]"); - return ret; - } - - return 0; -} - - -static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv, - const u8 *wpa_ie, size_t wpa_ie_len) -{ - struct prism2_hostapd_param *param; - int res; - size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len; - if (blen < sizeof(*param)) - blen = sizeof(*param); - - param = os_zalloc(blen); - if (param == NULL) - return -1; - - param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT; - param->u.generic_elem.len = wpa_ie_len; - os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len); - res = hostapd_ioctl(drv, param, blen, 1); - - os_free(param); - - return res; -} - - -static int prism2param(struct wpa_driver_hostap_data *drv, int param, - int value) -{ - struct iwreq iwr; - int *i, ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - i = (int *) iwr.u.name; - *i++ = param; - *i++ = value; - - if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) { - perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]"); - ret = -1; - } - return ret; -} - - -static int wpa_driver_hostap_set_wpa(void *priv, int enabled) -{ - struct wpa_driver_hostap_data *drv = priv; - int ret = 0; - - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); - - if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0) - ret = -1; - if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0) - ret = -1; - if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0) - ret = -1; - - return ret; -} - - -static void show_set_key_error(struct prism2_hostapd_param *param) -{ - switch (param->u.crypt.err) { - case HOSTAP_CRYPT_ERR_UNKNOWN_ALG: - wpa_printf(MSG_INFO, "Unknown algorithm '%s'.", - param->u.crypt.alg); - wpa_printf(MSG_INFO, "You may need to load kernel module to " - "register that algorithm."); - wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for " - "WEP."); - break; - case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR: - wpa_printf(MSG_INFO, "Unknown address " MACSTR ".", - MAC2STR(param->sta_addr)); - break; - case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED: - wpa_printf(MSG_INFO, "Crypt algorithm initialization failed."); - break; - case HOSTAP_CRYPT_ERR_KEY_SET_FAILED: - wpa_printf(MSG_INFO, "Key setting failed."); - break; - case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED: - wpa_printf(MSG_INFO, "TX key index setting failed."); - break; - case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED: - wpa_printf(MSG_INFO, "Card configuration failed."); - break; - } -} - - -static int wpa_driver_hostap_set_key(const char *ifname, void *priv, - enum wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) -{ - struct wpa_driver_hostap_data *drv = priv; - struct prism2_hostapd_param *param; - u8 *buf; - size_t blen; - int ret = 0; - char *alg_name; - - switch (alg) { - case WPA_ALG_NONE: - alg_name = "none"; - break; - case WPA_ALG_WEP: - alg_name = "WEP"; - break; - case WPA_ALG_TKIP: - alg_name = "TKIP"; - break; - case WPA_ALG_CCMP: - alg_name = "CCMP"; - break; - default: - return -1; - } - - wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu " - "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx, - (unsigned long) seq_len, (unsigned long) key_len); - - if (seq_len > 8) - return -2; - - blen = sizeof(*param) + key_len; - buf = os_zalloc(blen); - if (buf == NULL) - return -1; - - param = (struct prism2_hostapd_param *) buf; - param->cmd = PRISM2_SET_ENCRYPTION; - /* TODO: In theory, STA in client mode can use five keys; four default - * keys for receiving (with keyidx 0..3) and one individual key for - * both transmitting and receiving (keyidx 0) _unicast_ packets. Now, - * keyidx 0 is reserved for this unicast use and default keys can only - * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported). - * This should be fine for more or less all cases, but for completeness - * sake, the driver could be enhanced to support the missing key. */ -#if 0 - if (addr == NULL) - os_memset(param->sta_addr, 0xff, ETH_ALEN); - else - os_memcpy(param->sta_addr, addr, ETH_ALEN); -#else - os_memset(param->sta_addr, 0xff, ETH_ALEN); -#endif - os_strlcpy((char *) param->u.crypt.alg, alg_name, - HOSTAP_CRYPT_ALG_NAME_LEN); - param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; - param->u.crypt.idx = key_idx; - if (seq) - os_memcpy(param->u.crypt.seq, seq, seq_len); - param->u.crypt.key_len = key_len; - os_memcpy((u8 *) (param + 1), key, key_len); - - if (hostapd_ioctl(drv, param, blen, 1)) { - wpa_printf(MSG_WARNING, "Failed to set encryption."); - show_set_key_error(param); - ret = -1; - } - os_free(buf); - - return ret; -} - - -static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled) -{ - struct wpa_driver_hostap_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); - return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled); -} - - -static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv, - int type) -{ - struct iwreq iwr; - int *i, ret = 0; - - wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type); - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - i = (int *) iwr.u.name; - *i++ = type; - - if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) { - perror("ioctl[PRISM2_IOCTL_RESET]"); - ret = -1; - } - return ret; -} - - -static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv, - const u8 *addr, int cmd, int reason_code) -{ - struct prism2_hostapd_param param; - int ret; - - /* There does not seem to be a better way of deauthenticating or - * disassociating with Prism2/2.5/3 than sending the management frame - * and then resetting the Port0 to make sure both the AP and the STA - * end up in disconnected state. */ - os_memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_MLME; - os_memcpy(param.sta_addr, addr, ETH_ALEN); - param.u.mlme.cmd = cmd; - param.u.mlme.reason_code = reason_code; - ret = hostapd_ioctl(drv, ¶m, sizeof(param), 1); - if (ret == 0) { - os_sleep(0, 100000); - ret = wpa_driver_hostap_reset(drv, 2); - } - return ret; -} - - -static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr, - int reason_code) -{ - struct wpa_driver_hostap_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH, - reason_code); -} - - -static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr, - int reason_code) -{ - struct wpa_driver_hostap_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC, - reason_code); -} - -static int -wpa_driver_hostap_associate(void *priv, - struct wpa_driver_associate_params *params) +static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr, + const u8 *addr, int qos) { - struct wpa_driver_hostap_data *drv = priv; - int ret = 0; - int allow_unencrypted_eapol; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); + struct ieee80211_hdr hdr; - if (prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, - params->drop_unencrypted) < 0) - ret = -1; - if (wpa_driver_hostap_set_auth_alg(drv, params->auth_alg) < 0) - ret = -1; - if (params->mode != drv->current_mode) { - /* At the moment, Host AP driver requires host_roaming=2 for - * infrastructure mode and host_roaming=0 for adhoc. */ - if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, - params->mode == IEEE80211_MODE_IBSS ? 0 : 2) < - 0) { - wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming", - __func__); - } - drv->current_mode = params->mode; - } - - if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED, - params->key_mgmt_suite != KEY_MGMT_NONE) < 0) - ret = -1; - if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie, - params->wpa_ie_len) < 0) - ret = -1; - if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0) - ret = -1; - if (params->freq && - wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) - ret = -1; - if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len) - < 0) - ret = -1; - if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) - ret = -1; + os_memset(&hdr, 0, sizeof(hdr)); - /* Allow unencrypted EAPOL messages even if pairwise keys are set when - * not using WPA. IEEE 802.1X specifies that these frames are not - * encrypted, but WPA encrypts them when pairwise keys are in use. */ - if (params->key_mgmt_suite == KEY_MGMT_802_1X || - params->key_mgmt_suite == KEY_MGMT_PSK) - allow_unencrypted_eapol = 0; - else - allow_unencrypted_eapol = 1; - - if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X, - allow_unencrypted_eapol) < 0) { - wpa_printf(MSG_DEBUG, "hostap: Failed to configure " - "ieee_802_1x param"); - /* Ignore this error.. driver_hostap.c can also be used with - * other drivers that do not support this prism2_param. */ - } - - return ret; -} - - -static int wpa_driver_hostap_scan(void *priv, - struct wpa_driver_scan_params *params) -{ - struct wpa_driver_hostap_data *drv = priv; - struct prism2_hostapd_param param; - int ret; - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - - if (ssid == NULL) { - /* Use standard Linux Wireless Extensions ioctl if possible - * because some drivers using hostap code in wpa_supplicant - * might not support Host AP specific scan request (with SSID - * info). */ - return wpa_driver_wext_scan(drv->wext, params); - } - - if (ssid_len > 32) - ssid_len = 32; - - os_memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_SCAN_REQ; - param.u.scan_req.ssid_len = ssid_len; - os_memcpy(param.u.scan_req.ssid, ssid, ssid_len); - ret = hostapd_ioctl(drv, ¶m, sizeof(param), 1); - - /* Not all drivers generate "scan completed" wireless event, so try to - * read results after a timeout. */ - eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext, - drv->ctx); - eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext, - drv->ctx); - - return ret; -} - - -static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg) -{ - struct wpa_driver_hostap_data *drv = priv; - int algs = 0; - - if (auth_alg & WPA_AUTH_ALG_OPEN) - algs |= 1; - if (auth_alg & WPA_AUTH_ALG_SHARED) - algs |= 2; - if (auth_alg & WPA_AUTH_ALG_LEAP) - algs |= 4; - if (algs == 0) - algs = 1; /* at least one algorithm should be set */ - - return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs); -} - - -static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid) -{ - struct wpa_driver_hostap_data *drv = priv; - return wpa_driver_wext_get_bssid(drv->wext, bssid); -} - - -static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid) -{ - struct wpa_driver_hostap_data *drv = priv; - return wpa_driver_wext_get_ssid(drv->wext, ssid); -} - - -static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv) -{ - struct wpa_driver_hostap_data *drv = priv; - return wpa_driver_wext_get_scan_results(drv->wext); -} - - -static int wpa_driver_hostap_set_operstate(void *priv, int state) -{ - struct wpa_driver_hostap_data *drv = priv; - return wpa_driver_wext_set_operstate(drv->wext, state); -} - - -static void * wpa_driver_hostap_init(void *ctx, const char *ifname) -{ - struct wpa_driver_hostap_data *drv; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->wext = wpa_driver_wext_init(ctx, ifname); - if (drv->wext == NULL) { - os_free(drv); - return NULL; - } - - drv->ctx = ctx; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - drv->sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->sock < 0) { - perror("socket"); - wpa_driver_wext_deinit(drv->wext); - os_free(drv); - return NULL; - } - - if (os_strncmp(ifname, "wlan", 4) == 0) { - /* - * Host AP driver may use both wlan# and wifi# interface in - * wireless events. - */ - char ifname2[IFNAMSIZ + 1]; - os_strlcpy(ifname2, ifname, sizeof(ifname2)); - os_memcpy(ifname2, "wifi", 4); - wpa_driver_wext_alternative_ifindex(drv->wext, ifname2); - } - - wpa_driver_hostap_set_wpa(drv, 1); - - return drv; -} + /* + * WLAN_FC_STYPE_NULLFUNC would be more appropriate, + * but it is apparently not retried so TX Exc events + * are not received for it. + * This is the reason the driver overrides the default + * handling. + */ + hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, + WLAN_FC_STYPE_DATA); + hdr.frame_control |= + host_to_le16(WLAN_FC_FROMDS); + os_memcpy(hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN); + os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); + os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); -static void wpa_driver_hostap_deinit(void *priv) -{ - struct wpa_driver_hostap_data *drv = priv; - wpa_driver_hostap_set_wpa(drv, 0); - wpa_driver_wext_deinit(drv->wext); - close(drv->sock); - os_free(drv); + hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0); } -#endif /* HOSTAPD */ - const struct wpa_driver_ops wpa_driver_hostap_ops = { .name = "hostap", .desc = "Host AP driver (Intersil Prism2/2.5/3)", .set_key = wpa_driver_hostap_set_key, -#ifdef HOSTAPD .hapd_init = hostap_init, .hapd_deinit = hostap_driver_deinit, .set_ieee8021x = hostap_set_ieee8021x, @@ -1632,17 +1194,6 @@ const struct wpa_driver_ops wpa_driver_hostap_ops = { .sta_clear_stats = hostap_sta_clear_stats, .get_hw_feature_data = hostap_get_hw_feature_data, .set_ap_wps_ie = hostap_set_ap_wps_ie, -#else /* HOSTAPD */ - .get_bssid = wpa_driver_hostap_get_bssid, - .get_ssid = wpa_driver_hostap_get_ssid, - .set_countermeasures = wpa_driver_hostap_set_countermeasures, - .scan2 = wpa_driver_hostap_scan, - .get_scan_results2 = wpa_driver_hostap_get_scan_results, - .deauthenticate = wpa_driver_hostap_deauthenticate, - .disassociate = wpa_driver_hostap_disassociate, - .associate = wpa_driver_hostap_associate, - .init = wpa_driver_hostap_init, - .deinit = wpa_driver_hostap_deinit, - .set_operstate = wpa_driver_hostap_set_operstate, -#endif /* HOSTAPD */ + .set_freq = hostap_set_freq, + .poll_client = wpa_driver_hostap_poll_client, }; diff --git a/src/drivers/driver_iphone.m b/src/drivers/driver_iphone.m deleted file mode 100644 index 8213fda..0000000 --- a/src/drivers/driver_iphone.m +++ /dev/null @@ -1,466 +0,0 @@ -/* - * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface - * Copyright (c) 2007, Jouni Malinen <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "includes.h" -#define Boolean __DummyBoolean -#include <CoreFoundation/CoreFoundation.h> -#undef Boolean - -#include "common.h" -#include "driver.h" -#include "eloop.h" -#include "common/ieee802_11_defs.h" - -#include "MobileApple80211.h" - -struct wpa_driver_iphone_data { - void *ctx; - Apple80211Ref wireless_ctx; - CFArrayRef scan_results; - int ctrl_power; -}; - - -static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key) -{ - const void *res; - CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key, - kCFStringEncodingMacRoman); - if (str == NULL) - return NULL; - - res = CFDictionaryGetValue(dict, str); - CFRelease(str); - return res; -} - - -static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid) -{ - struct wpa_driver_iphone_data *drv = priv; - CFDataRef data; - int err, len; - - err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0, - &data); - if (err != 0) { - wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) " - "failed: %d", err); - return -1; - } - - len = CFDataGetLength(data); - if (len > 32) { - CFRelease(data); - return -1; - } - os_memcpy(ssid, CFDataGetBytePtr(data), len); - CFRelease(data); - - return len; -} - - -static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid) -{ - struct wpa_driver_iphone_data *drv = priv; - CFStringRef data; - int err; - int a1, a2, a3, a4, a5, a6; - - err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0, - &data); - if (err != 0) { - wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) " - "failed: %d", err); - return -1; - } - - sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman), - "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6); - bssid[0] = a1; - bssid[1] = a2; - bssid[2] = a3; - bssid[3] = a4; - bssid[4] = a5; - bssid[5] = a6; - - CFRelease(data); - - return 0; -} - - -static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx) -{ - wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -} - - -static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len) -{ - struct wpa_driver_iphone_data *drv = priv; - int err; - - if (drv->scan_results) { - CFRelease(drv->scan_results); - drv->scan_results = NULL; - } - - err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL); - if (err) { - wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d", - err); - return -1; - } - - eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv, - drv->ctx); - return 0; -} - - -static int wpa_driver_iphone_get_scan_results(void *priv, - struct wpa_scan_result *results, - size_t max_size) -{ - struct wpa_driver_iphone_data *drv = priv; - size_t i, num; - - if (drv->scan_results == NULL) - return 0; - - num = CFArrayGetCount(drv->scan_results); - if (num > max_size) - num = max_size; - os_memset(results, 0, num * sizeof(struct wpa_scan_result)); - - for (i = 0; i < num; i++) { - struct wpa_scan_result *res = &results[i]; - CFDictionaryRef dict = - CFArrayGetValueAtIndex(drv->scan_results, i); - CFDataRef data; - CFStringRef str; - CFNumberRef num; - int val; - - data = cfdict_get_key_str(dict, "SSID"); - if (data) { - res->ssid_len = CFDataGetLength(data); - if (res->ssid_len > 32) - res->ssid_len = 32; - os_memcpy(res->ssid, CFDataGetBytePtr(data), - res->ssid_len); - } - - str = cfdict_get_key_str(dict, "BSSID"); - if (str) { - int a1, a2, a3, a4, a5, a6; - sscanf(CFStringGetCStringPtr( - str, kCFStringEncodingMacRoman), - "%x:%x:%x:%x:%x:%x", - &a1, &a2, &a3, &a4, &a5, &a6); - res->bssid[0] = a1; - res->bssid[1] = a2; - res->bssid[2] = a3; - res->bssid[3] = a4; - res->bssid[4] = a5; - res->bssid[5] = a6; - } - - num = cfdict_get_key_str(dict, "CAPABILITIES"); - if (num) { - if (CFNumberGetValue(num, kCFNumberSInt32Type, &val)) - res->caps = val; - } - - num = cfdict_get_key_str(dict, "CHANNEL"); - if (num) { - if (CFNumberGetValue(num, kCFNumberSInt32Type, &val)) - res->freq = 2407 + val * 5; - } - - num = cfdict_get_key_str(dict, "RSSI"); - if (num) { - if (CFNumberGetValue(num, kCFNumberSInt32Type, &val)) - res->level = val; - } - - num = cfdict_get_key_str(dict, "NOISE"); - if (num) { - if (CFNumberGetValue(num, kCFNumberSInt32Type, &val)) - res->noise = val; - } - - data = cfdict_get_key_str(dict, "IE"); - if (data) { - u8 *ptr = (u8 *) CFDataGetBytePtr(data); - int len = CFDataGetLength(data); - u8 *pos = ptr, *end = ptr + len; - - while (pos + 2 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == WLAN_EID_RSN && - pos[1] <= SSID_MAX_WPA_IE_LEN) { - os_memcpy(res->rsn_ie, pos, - 2 + pos[1]); - res->rsn_ie_len = 2 + pos[1]; - } - if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && - pos[1] > 4 && pos[2] == 0x00 && - pos[3] == 0x50 && pos[4] == 0xf2 && - pos[5] == 0x01) { - os_memcpy(res->wpa_ie, pos, - 2 + pos[1]); - res->wpa_ie_len = 2 + pos[1]; - } - - pos = pos + 2 + pos[1]; - } - } - } - - return num; -} - - -static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_driver_iphone_data *drv = eloop_ctx; - u8 bssid[ETH_ALEN]; - - if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) { - eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout, - drv, drv->ctx); - return; - } - - wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL); -} - - -static int wpa_driver_iphone_associate( - void *priv, struct wpa_driver_associate_params *params) -{ - struct wpa_driver_iphone_data *drv = priv; - int i, num, err; - size_t ssid_len; - CFDictionaryRef bss = NULL; - - /* - * TODO: Consider generating parameters instead of just using an entry - * from scan results in order to support ap_scan=2. - */ - - if (drv->scan_results == NULL) { - wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot " - "associate"); - return -1; - } - - num = CFArrayGetCount(drv->scan_results); - - for (i = 0; i < num; i++) { - CFDictionaryRef dict = - CFArrayGetValueAtIndex(drv->scan_results, i); - CFDataRef data; - - data = cfdict_get_key_str(dict, "SSID"); - if (data == NULL) - continue; - - ssid_len = CFDataGetLength(data); - if (ssid_len != params->ssid_len || - os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len) - != 0) - continue; - - bss = dict; - break; - } - - if (bss == NULL) { - wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan " - "results - cannot associate"); - return -1; - } - - wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found " - "from scan results"); - - err = Apple80211Associate(drv->wireless_ctx, bss, NULL); - if (err) { - wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: " - "%d", err); - return -1; - } - - /* - * Driver is actually already associated; report association from an - * eloop callback. - */ - eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx); - eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv, - drv->ctx); - - return 0; -} - - -static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, const u8 *seq, - size_t seq_len, const u8 *key, - size_t key_len) -{ - /* - * TODO: Need to either support configuring PMK for 4-way handshake or - * PTK for TKIP/CCMP. - */ - return -1; -} - - -static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa) -{ - os_memset(capa, 0, sizeof(*capa)); - - capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; - capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 | - WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP; - capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | - WPA_DRIVER_AUTH_LEAP; - capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; - - return 0; -} - - -static void * wpa_driver_iphone_init(void *ctx, const char *ifname) -{ - struct wpa_driver_iphone_data *drv; - int err; - char power; - CFStringRef name; - CFDictionaryRef dict; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->ctx = ctx; - err = Apple80211Open(&drv->wireless_ctx); - if (err) { - wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d", - err); - os_free(drv); - return NULL; - } - - name = CFStringCreateWithCString(kCFAllocatorDefault, ifname, - kCFStringEncodingISOLatin1); - if (name == NULL) { - wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed"); - Apple80211Close(drv->wireless_ctx); - os_free(drv); - return NULL; - } - - err = Apple80211BindToInterface(drv->wireless_ctx, name); - CFRelease(name); - - if (err) { - wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface " - "failed: %d", err); - Apple80211Close(drv->wireless_ctx); - os_free(drv); - return NULL; - } - - err = Apple80211GetPower(drv->wireless_ctx, &power); - if (err) - wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d", - err); - - wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power); - - if (!power) { - drv->ctrl_power = 1; - err = Apple80211SetPower(drv->wireless_ctx, 1); - if (err) { - wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower " - "failed: %d", err); - Apple80211Close(drv->wireless_ctx); - os_free(drv); - return NULL; - } - } - - err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict); - if (err == 0) { - CFShow(dict); - CFRelease(dict); - } else { - printf("Apple80211GetInfoCopy: %d\n", err); - } - - return drv; -} - - -static void wpa_driver_iphone_deinit(void *priv) -{ - struct wpa_driver_iphone_data *drv = priv; - int err; - - eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx); - eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx); - - if (drv->ctrl_power) { - wpa_printf(MSG_DEBUG, "iPhone: Power down the interface"); - err = Apple80211SetPower(drv->wireless_ctx, 0); - if (err) { - wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) " - "failed: %d", err); - } - } - - err = Apple80211Close(drv->wireless_ctx); - if (err) { - wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d", - err); - } - - if (drv->scan_results) - CFRelease(drv->scan_results); - - os_free(drv); -} - - -const struct wpa_driver_ops wpa_driver_iphone_ops = { - .name = "iphone", - .desc = "iPhone/iPod touch Apple80211 driver", - .get_ssid = wpa_driver_iphone_get_ssid, - .get_bssid = wpa_driver_iphone_get_bssid, - .init = wpa_driver_iphone_init, - .deinit = wpa_driver_iphone_deinit, - .scan = wpa_driver_iphone_scan, - .get_scan_results = wpa_driver_iphone_get_scan_results, - .associate = wpa_driver_iphone_associate, - .set_key = wpa_driver_iphone_set_key, - .get_capa = wpa_driver_iphone_get_capa, -}; diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c index 630fbf4..edb086f 100644 --- a/src/drivers/driver_madwifi.c +++ b/src/drivers/driver_madwifi.c @@ -27,7 +27,7 @@ #include "driver_wext.h" #include "eloop.h" #include "common/ieee802_11_defs.h" -#include "wireless_copy.h" +#include "linux_wext.h" /* * Avoid conflicts with wpa_supplicant definitions by undefining a definition. @@ -71,8 +71,6 @@ #define WPA_KEY_RSC_LEN 8 -#ifdef HOSTAPD - #include "priv_netlink.h" #include "netlink.h" #include "linux_ioctl.h" @@ -734,6 +732,8 @@ static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, os_memset(&event, 0, sizeof(event)); event.rx_probe_req.sa = mgmt->sa; + event.rx_probe_req.da = mgmt->da; + event.rx_probe_req.bssid = mgmt->bssid; event.rx_probe_req.ie = mgmt->u.probe_req.variable; event.rx_probe_req.ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); @@ -804,6 +804,24 @@ madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, #define madwifi_set_ap_wps_ie NULL #endif /* CONFIG_WPS */ +static int madwifi_set_freq(void *priv, struct hostapd_freq_params *freq) +{ + struct madwifi_driver_data *drv = priv; + struct iwreq iwr; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.freq.m = freq->channel; + iwr.u.freq.e = 0; + + if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { + perror("ioctl[SIOCSIWFREQ]"); + return -1; + } + + return 0; +} + static void madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) { @@ -1274,554 +1292,11 @@ madwifi_commit(void *priv) return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); } -#else /* HOSTAPD */ - -struct wpa_driver_madwifi_data { - void *wext; /* private data for driver_wext */ - void *ctx; - char ifname[IFNAMSIZ + 1]; - int sock; -}; - -static int wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg); -static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies, - size_t ies_len); - - -static int -set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len, - int show_err) -{ - struct iwreq iwr; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - if (len < IFNAMSIZ && - op != IEEE80211_IOCTL_SET_APPIEBUF) { - /* - * Argument data fits inline; put it there. - */ - os_memcpy(iwr.u.name, data, len); - } else { - /* - * Argument data too big for inline transfer; setup a - * parameter block instead; the kernel will transfer - * the data for the driver. - */ - iwr.u.data.pointer = data; - iwr.u.data.length = len; - } - - if (ioctl(drv->sock, op, &iwr) < 0) { - if (show_err) { -#ifdef MADWIFI_NG - int first = IEEE80211_IOCTL_SETPARAM; - int last = IEEE80211_IOCTL_KICKMAC; - static const char *opnames[] = { - "ioctl[IEEE80211_IOCTL_SETPARAM]", - "ioctl[IEEE80211_IOCTL_GETPARAM]", - "ioctl[IEEE80211_IOCTL_SETMODE]", - "ioctl[IEEE80211_IOCTL_GETMODE]", - "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]", - "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]", - "ioctl[IEEE80211_IOCTL_SETCHANLIST]", - "ioctl[IEEE80211_IOCTL_GETCHANLIST]", - "ioctl[IEEE80211_IOCTL_CHANSWITCH]", - NULL, - "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]", - "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]", - NULL, - "ioctl[IEEE80211_IOCTL_GETCHANINFO]", - "ioctl[IEEE80211_IOCTL_SETOPTIE]", - "ioctl[IEEE80211_IOCTL_GETOPTIE]", - "ioctl[IEEE80211_IOCTL_SETMLME]", - NULL, - "ioctl[IEEE80211_IOCTL_SETKEY]", - NULL, - "ioctl[IEEE80211_IOCTL_DELKEY]", - NULL, - "ioctl[IEEE80211_IOCTL_ADDMAC]", - NULL, - "ioctl[IEEE80211_IOCTL_DELMAC]", - NULL, - "ioctl[IEEE80211_IOCTL_WDSMAC]", - NULL, - "ioctl[IEEE80211_IOCTL_WDSDELMAC]", - NULL, - "ioctl[IEEE80211_IOCTL_KICKMAC]", - }; -#else /* MADWIFI_NG */ - int first = IEEE80211_IOCTL_SETPARAM; - int last = IEEE80211_IOCTL_CHANLIST; - static const char *opnames[] = { - "ioctl[IEEE80211_IOCTL_SETPARAM]", - "ioctl[IEEE80211_IOCTL_GETPARAM]", - "ioctl[IEEE80211_IOCTL_SETKEY]", - "ioctl[IEEE80211_IOCTL_GETKEY]", - "ioctl[IEEE80211_IOCTL_DELKEY]", - NULL, - "ioctl[IEEE80211_IOCTL_SETMLME]", - NULL, - "ioctl[IEEE80211_IOCTL_SETOPTIE]", - "ioctl[IEEE80211_IOCTL_GETOPTIE]", - "ioctl[IEEE80211_IOCTL_ADDMAC]", - NULL, - "ioctl[IEEE80211_IOCTL_DELMAC]", - NULL, - "ioctl[IEEE80211_IOCTL_CHANLIST]", - }; -#endif /* MADWIFI_NG */ - int idx = op - first; - if (first <= op && op <= last && - idx < (int) (sizeof(opnames) / sizeof(opnames[0])) - && opnames[idx]) - perror(opnames[idx]); - else - perror("ioctl[unknown???]"); - } - return -1; - } - return 0; -} - -static int -set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg, - int show_err) -{ - struct iwreq iwr; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.mode = op; - os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg)); - - if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { - if (show_err) - perror("ioctl[IEEE80211_IOCTL_SETPARAM]"); - return -1; - } - return 0; -} - -static int -wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv, - const u8 *wpa_ie, size_t wpa_ie_len) -{ - struct iwreq iwr; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - /* NB: SETOPTIE is not fixed-size so must not be inlined */ - iwr.u.data.pointer = (void *) wpa_ie; - iwr.u.data.length = wpa_ie_len; - - if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) { - perror("ioctl[IEEE80211_IOCTL_SETOPTIE]"); - return -1; - } - return 0; -} - -static int -wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx, - const u8 *addr) -{ - struct ieee80211req_del_key wk; - - wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx); - os_memset(&wk, 0, sizeof(wk)); - wk.idk_keyix = key_idx; - if (addr != NULL) - os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); - - return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1); -} - -static int -wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, - const u8 *addr, int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) -{ - struct wpa_driver_madwifi_data *drv = priv; - struct ieee80211req_key wk; - char *alg_name; - u_int8_t cipher; - - if (alg == WPA_ALG_NONE) - return wpa_driver_madwifi_del_key(drv, key_idx, addr); - - switch (alg) { - case WPA_ALG_WEP: - if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", - ETH_ALEN) == 0) { - /* - * madwifi did not seem to like static WEP key - * configuration with IEEE80211_IOCTL_SETKEY, so use - * Linux wireless extensions ioctl for this. - */ - return wpa_driver_wext_set_key(ifname, drv->wext, alg, - addr, key_idx, set_tx, - seq, seq_len, - key, key_len); - } - alg_name = "WEP"; - cipher = IEEE80211_CIPHER_WEP; - break; - case WPA_ALG_TKIP: - alg_name = "TKIP"; - cipher = IEEE80211_CIPHER_TKIP; - break; - case WPA_ALG_CCMP: - alg_name = "CCMP"; - cipher = IEEE80211_CIPHER_AES_CCM; - break; - default: - wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d", - __FUNCTION__, alg); - return -1; - } - - wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu " - "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx, - (unsigned long) seq_len, (unsigned long) key_len); - - if (seq_len > sizeof(u_int64_t)) { - wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big", - __FUNCTION__, (unsigned long) seq_len); - return -2; - } - if (key_len > sizeof(wk.ik_keydata)) { - wpa_printf(MSG_DEBUG, "%s: key length %lu too big", - __FUNCTION__, (unsigned long) key_len); - return -3; - } - - os_memset(&wk, 0, sizeof(wk)); - wk.ik_type = cipher; - wk.ik_flags = IEEE80211_KEY_RECV; - if (addr == NULL || - os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) - wk.ik_flags |= IEEE80211_KEY_GROUP; - if (set_tx) { - wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT; - os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - } else - os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN); - wk.ik_keyix = key_idx; - wk.ik_keylen = key_len; -#ifdef WORDS_BIGENDIAN - if (seq) { - size_t i; - u8 tmp[WPA_KEY_RSC_LEN]; - os_memset(tmp, 0, sizeof(tmp)); - for (i = 0; i < seq_len; i++) - tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i]; - os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN); - } -#else /* WORDS_BIGENDIAN */ - if (seq) - os_memcpy(&wk.ik_keyrsc, seq, seq_len); -#endif /* WORDS_BIGENDIAN */ - os_memcpy(wk.ik_keydata, key, key_len); - - return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1); -} - -static int -wpa_driver_madwifi_set_countermeasures(void *priv, int enabled) -{ - struct wpa_driver_madwifi_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); - return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1); -} - -static int -wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code) -{ - struct wpa_driver_madwifi_data *drv = priv; - struct ieee80211req_mlme mlme; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - mlme.im_op = IEEE80211_MLME_DEAUTH; - mlme.im_reason = reason_code; - os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1); -} - -static int -wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code) -{ - struct wpa_driver_madwifi_data *drv = priv; - struct ieee80211req_mlme mlme; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - mlme.im_op = IEEE80211_MLME_DISASSOC; - mlme.im_reason = reason_code; - os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1); -} - -static int -wpa_driver_madwifi_associate(void *priv, - struct wpa_driver_associate_params *params) -{ - struct wpa_driver_madwifi_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret = 0, privacy = 1; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, - params->drop_unencrypted, 1) < 0) - ret = -1; - if (wpa_driver_madwifi_set_auth_alg(drv, params->auth_alg) < 0) - ret = -1; - - /* - * NB: Don't need to set the freq or cipher-related state as - * this is implied by the bssid which is used to locate - * the scanned node state which holds it. The ssid is - * needed to disambiguate an AP that broadcasts multiple - * ssid's but uses the same bssid. - */ - /* XXX error handling is wrong but unclear what to do... */ - if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie, - params->wpa_ie_len) < 0) - ret = -1; - - if (params->pairwise_suite == CIPHER_NONE && - params->group_suite == CIPHER_NONE && - params->key_mgmt_suite == KEY_MGMT_NONE && - params->wpa_ie_len == 0) - privacy = 0; - - if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0) - ret = -1; - - if (params->wpa_ie_len && - set80211param(drv, IEEE80211_PARAM_WPA, - params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0) - ret = -1; - - if (params->bssid == NULL) { - /* ap_scan=2 mode - driver takes care of AP selection and - * roaming */ - /* FIX: this does not seem to work; would probably need to - * change something in the driver */ - if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) - ret = -1; - - if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, - params->ssid_len) < 0) - ret = -1; - } else { - if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) - ret = -1; - if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, - params->ssid_len) < 0) - ret = -1; - os_memset(&mlme, 0, sizeof(mlme)); - mlme.im_op = IEEE80211_MLME_ASSOC; - os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN); - if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, - sizeof(mlme), 1) < 0) { - wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed", - __func__); - ret = -1; - } - } - - return ret; -} - -static int -wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg) -{ - struct wpa_driver_madwifi_data *drv = priv; - int authmode; - - if ((auth_alg & WPA_AUTH_ALG_OPEN) && - (auth_alg & WPA_AUTH_ALG_SHARED)) - authmode = IEEE80211_AUTH_AUTO; - else if (auth_alg & WPA_AUTH_ALG_SHARED) - authmode = IEEE80211_AUTH_SHARED; - else - authmode = IEEE80211_AUTH_OPEN; - - return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1); -} - -static int -wpa_driver_madwifi_scan(void *priv, struct wpa_driver_scan_params *params) -{ - struct wpa_driver_madwifi_data *drv = priv; - struct iwreq iwr; - int ret = 0; - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - - wpa_driver_madwifi_set_probe_req_ie(drv, params->extra_ies, - params->extra_ies_len); - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - - /* set desired ssid before scan */ - /* FIX: scan should not break the current association, so using - * set_ssid may not be the best way of doing this.. */ - if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0) - ret = -1; - - if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) { - perror("ioctl[SIOCSIWSCAN]"); - ret = -1; - } - - /* - * madwifi delivers a scan complete event so no need to poll, but - * register a backup timeout anyway to make sure that we recover even - * if the driver does not send this event for any reason. This timeout - * will only be used if the event is not delivered (event handler will - * cancel the timeout). - */ - eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext, - drv->ctx); - eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext, - drv->ctx); - - return ret; -} - -static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid) -{ - struct wpa_driver_madwifi_data *drv = priv; - return wpa_driver_wext_get_bssid(drv->wext, bssid); -} - - -static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid) -{ - struct wpa_driver_madwifi_data *drv = priv; - return wpa_driver_wext_get_ssid(drv->wext, ssid); -} - - -static struct wpa_scan_results * -wpa_driver_madwifi_get_scan_results(void *priv) -{ - struct wpa_driver_madwifi_data *drv = priv; - return wpa_driver_wext_get_scan_results(drv->wext); -} - - -static int wpa_driver_madwifi_set_operstate(void *priv, int state) -{ - struct wpa_driver_madwifi_data *drv = priv; - return wpa_driver_wext_set_operstate(drv->wext, state); -} - - -static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies, - size_t ies_len) -{ - struct ieee80211req_getset_appiebuf *probe_req_ie; - int ret; - - probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len); - if (probe_req_ie == NULL) - return -1; - - probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ; - probe_req_ie->app_buflen = ies_len; - os_memcpy(probe_req_ie->app_buf, ies, ies_len); - - ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie, - sizeof(struct ieee80211req_getset_appiebuf) + - ies_len, 1); - - os_free(probe_req_ie); - - return ret; -} - - -static void * wpa_driver_madwifi_init(void *ctx, const char *ifname) -{ - struct wpa_driver_madwifi_data *drv; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->wext = wpa_driver_wext_init(ctx, ifname); - if (drv->wext == NULL) - goto fail; - - drv->ctx = ctx; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - drv->sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->sock < 0) - goto fail2; - - if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) { - wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based " - "roaming", __FUNCTION__); - goto fail3; - } - - if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) { - wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support", - __FUNCTION__); - goto fail3; - } - - return drv; - -fail3: - close(drv->sock); -fail2: - wpa_driver_wext_deinit(drv->wext); -fail: - os_free(drv); - return NULL; -} - - -static void wpa_driver_madwifi_deinit(void *priv) -{ - struct wpa_driver_madwifi_data *drv = priv; - - if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) { - wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE", - __FUNCTION__); - } - if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) { - wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based " - "roaming", __FUNCTION__); - } - if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) { - wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy " - "flag", __FUNCTION__); - } - if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) { - wpa_printf(MSG_DEBUG, "%s: failed to disable WPA", - __FUNCTION__); - } - - wpa_driver_wext_deinit(drv->wext); - - close(drv->sock); - os_free(drv); -} - -#endif /* HOSTAPD */ - const struct wpa_driver_ops wpa_driver_madwifi_ops = { .name = "madwifi", .desc = "MADWIFI 802.11 support (Atheros, etc.)", .set_key = wpa_driver_madwifi_set_key, -#ifdef HOSTAPD .hapd_init = madwifi_init, .hapd_deinit = madwifi_deinit, .set_ieee8021x = madwifi_set_ieee8021x, @@ -1840,17 +1315,5 @@ const struct wpa_driver_ops wpa_driver_madwifi_ops = { .sta_clear_stats = madwifi_sta_clear_stats, .commit = madwifi_commit, .set_ap_wps_ie = madwifi_set_ap_wps_ie, -#else /* HOSTAPD */ - .get_bssid = wpa_driver_madwifi_get_bssid, - .get_ssid = wpa_driver_madwifi_get_ssid, - .init = wpa_driver_madwifi_init, - .deinit = wpa_driver_madwifi_deinit, - .set_countermeasures = wpa_driver_madwifi_set_countermeasures, - .scan2 = wpa_driver_madwifi_scan, - .get_scan_results2 = wpa_driver_madwifi_get_scan_results, - .deauthenticate = wpa_driver_madwifi_deauthenticate, - .disassociate = wpa_driver_madwifi_disassociate, - .associate = wpa_driver_madwifi_associate, - .set_operstate = wpa_driver_madwifi_set_operstate, -#endif /* HOSTAPD */ + .set_freq = madwifi_set_freq, }; diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index aeb7304..dbe9a28 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -3213,119 +3213,33 @@ wpa_driver_ndis_get_interfaces(void *global_priv) } -const struct wpa_driver_ops wpa_driver_ndis_ops = { - "ndis", - "Windows NDIS driver", - wpa_driver_ndis_get_bssid, - wpa_driver_ndis_get_ssid, - wpa_driver_ndis_set_key, - wpa_driver_ndis_init, - wpa_driver_ndis_deinit, - NULL /* set_param */, - NULL /* set_countermeasures */, - wpa_driver_ndis_deauthenticate, - wpa_driver_ndis_disassociate, - wpa_driver_ndis_associate, - wpa_driver_ndis_add_pmkid, - wpa_driver_ndis_remove_pmkid, - wpa_driver_ndis_flush_pmkid, - wpa_driver_ndis_get_capa, - wpa_driver_ndis_poll, - wpa_driver_ndis_get_ifname, - wpa_driver_ndis_get_mac_addr, - NULL /* send_eapol */, - NULL /* set_operstate */, - NULL /* mlme_setprotection */, - NULL /* get_hw_feature_data */, - NULL /* set_channel */, - NULL /* set_ssid */, - NULL /* set_bssid */, - NULL /* send_mlme */, - NULL /* mlme_add_sta */, - NULL /* mlme_remove_sta */, - NULL /* update_ft_ies */, - NULL /* send_ft_action */, - wpa_driver_ndis_get_scan_results, - NULL /* set_country */, - NULL /* global_init */, - NULL /* global_deinit */, - NULL /* init2 */, - wpa_driver_ndis_get_interfaces, - wpa_driver_ndis_scan, - NULL /* authenticate */, - NULL /* set_beacon */, - NULL /* hapd_init */, - NULL /* hapd_deinit */, - NULL /* set_ieee8021x */, - NULL /* set_privacy */, - NULL /* get_seqnum */, - NULL /* flush */, - NULL /* set_generic_elem */, - NULL /* read_sta_data */, - NULL /* hapd_send_eapol */, - NULL /* sta_deauth */, - NULL /* sta_disassoc */, - NULL /* sta_remove */, - NULL /* hapd_get_ssid */, - NULL /* hapd_set_ssid */, - NULL /* hapd_set_countermeasures */, - NULL /* sta_add */, - NULL /* get_inact_sec */, - NULL /* sta_clear_stats */, - NULL /* set_freq */, - NULL /* set_rts */, - NULL /* set_frag */, - NULL /* sta_set_flags */, - NULL /* set_rate_sets */, - NULL /* set_cts_protect */, - NULL /* set_preamble */, - NULL /* set_short_slot_time */, - NULL /* set_tx_queue_params */, - NULL /* valid_bss_mask */, - NULL /* if_add */, - NULL /* if_remove */, - NULL /* set_sta_vlan */, - NULL /* commit */, - NULL /* send_ether */, - NULL /* set_radius_acl_auth */, - NULL /* set_radius_acl_expire */, - NULL /* set_ht_params */, - NULL /* set_ap_wps_ie */, - NULL /* set_supp_port */, - NULL /* set_wds_sta */, - NULL /* send_action */, - NULL /* send_action_cancel_wait */, - NULL /* remain_on_channel */, - NULL /* cancel_remain_on_channel */, - NULL /* probe_req_report */, - NULL /* disable_11b_rates */, - NULL /* deinit_ap */, - NULL /* suspend */, - NULL /* resume */, - NULL /* signal_monitor */, - NULL /* send_frame */, - NULL /* shared_freq */, - NULL /* get_noa */, - NULL /* set_noa */, - NULL /* set_p2p_powersave */, - NULL /* ampdu */, - NULL /* set_intra_bss */, - NULL /* get_radio_name */, - NULL /* p2p_find */, - NULL /* p2p_stop_find */, - NULL /* p2p_listen */, - NULL /* p2p_connect */, - NULL /* wps_success_cb */, - NULL /* p2p_group_formation_failed */, - NULL /* p2p_set_params */, - NULL /* p2p_prov_disc_req */, - NULL /* p2p_sd_request */, - NULL /* p2p_sd_cancel_request */, - NULL /* p2p_sd_response */, - NULL /* p2p_service_update */, - NULL /* p2p_reject */, - NULL /* p2p_invite */, - NULL /* send_tdls_mgmt */, - NULL /* tdls_oper */, - NULL /* signal_poll */ -}; +static const char *ndis_drv_name = "ndis"; +static const char *ndis_drv_desc = "Windows NDIS driver"; + +struct wpa_driver_ops wpa_driver_ndis_ops; + +void driver_ndis_init_ops(void) +{ + os_memset(&wpa_driver_ndis_ops, 0, sizeof(wpa_driver_ndis_ops)); + wpa_driver_ndis_ops.name = ndis_drv_name; + wpa_driver_ndis_ops.desc = ndis_drv_desc; + wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid; + wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid; + wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key; + wpa_driver_ndis_ops.init = wpa_driver_ndis_init; + wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit; + wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate; + wpa_driver_ndis_ops.disassociate = wpa_driver_ndis_disassociate; + wpa_driver_ndis_ops.associate = wpa_driver_ndis_associate; + wpa_driver_ndis_ops.add_pmkid = wpa_driver_ndis_add_pmkid; + wpa_driver_ndis_ops.remove_pmkid = wpa_driver_ndis_remove_pmkid; + wpa_driver_ndis_ops.flush_pmkid = wpa_driver_ndis_flush_pmkid; + wpa_driver_ndis_ops.get_capa = wpa_driver_ndis_get_capa; + wpa_driver_ndis_ops.poll = wpa_driver_ndis_poll; + wpa_driver_ndis_ops.get_ifname = wpa_driver_ndis_get_ifname; + wpa_driver_ndis_ops.get_mac_addr = wpa_driver_ndis_get_mac_addr; + wpa_driver_ndis_ops.get_scan_results2 = + wpa_driver_ndis_get_scan_results; + wpa_driver_ndis_ops.get_interfaces = wpa_driver_ndis_get_interfaces; + wpa_driver_ndis_ops.scan2 = wpa_driver_ndis_scan; +} diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index df309c5..a00f703 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -28,21 +28,47 @@ #include <linux/rtnetlink.h> #include <netpacket/packet.h> #include <linux/filter.h> +#include <linux/errqueue.h> #include "nl80211_copy.h" #include "common.h" #include "eloop.h" #include "utils/list.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "l2_packet/l2_packet.h" #include "netlink.h" #include "linux_ioctl.h" #include "radiotap.h" #include "radiotap_iter.h" #include "rfkill.h" #include "driver.h" -#if defined(ANDROID_BRCM_P2P_PATCH) && !defined(HOSTAPD) +#if defined(ANDROID_P2P) && !defined(HOSTAPD) #include "wpa_supplicant_i.h" #endif +#ifndef SO_WIFI_STATUS +# if defined(__sparc__) +# define SO_WIFI_STATUS 0x0025 +# elif defined(__parisc__) +# define SO_WIFI_STATUS 0x4022 +# else +# define SO_WIFI_STATUS 41 +# endif + +# define SCM_WIFI_STATUS SO_WIFI_STATUS +#endif + +#ifndef SO_EE_ORIGIN_TXSTATUS +#define SO_EE_ORIGIN_TXSTATUS 4 +#endif + +#ifndef PACKET_TX_TIMESTAMP +#define PACKET_TX_TIMESTAMP 16 +#endif + +#ifdef ANDROID +#include "android_drv.h" +#endif /* ANDROID */ #ifdef CONFIG_LIBNL20 /* libnl 2.0 compatibility code */ #define nl_handle nl_sock @@ -91,6 +117,37 @@ static void nl80211_handle_destroy(struct nl_handle *handle) #endif /* CONFIG_LIBNL20 */ +static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg) +{ + struct nl_handle *handle; + + handle = nl80211_handle_alloc(cb); + if (handle == NULL) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " + "callbacks (%s)", dbg); + return NULL; + } + + if (genl_connect(handle)) { + wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " + "netlink (%s)", dbg); + nl80211_handle_destroy(handle); + return NULL; + } + + return handle; +} + + +static void nl_destroy_handles(struct nl_handle **handle) +{ + if (*handle == NULL) + return; + nl80211_handle_destroy(*handle); + *handle = NULL; +} + + #ifndef IFF_LOWER_UP #define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ #endif @@ -107,8 +164,30 @@ static void nl80211_handle_destroy(struct nl_handle *handle) struct nl80211_global { struct dl_list interfaces; + int if_add_ifindex; + struct netlink_data *netlink; + struct nl_cb *nl_cb; + struct nl_handle *nl; + int nl80211_id; + int ioctl_sock; /* socket for ioctl() use */ + + struct nl_handle *nl_event; }; +struct nl80211_wiphy_data { + struct dl_list list; + struct dl_list bsss; + struct dl_list drvs; + + struct nl_handle *nl_beacons; + struct nl_cb *nl_cb; + + int wiphy_idx; +}; + +static void nl80211_global_deinit(void *priv); +static void wpa_driver_nl80211_deinit(void *priv); + struct i802_bss { struct wpa_driver_nl80211_data *drv; struct i802_bss *next; @@ -118,19 +197,28 @@ struct i802_bss { unsigned int beacon_set:1; unsigned int added_if_into_bridge:1; unsigned int added_bridge:1; + + u8 addr[ETH_ALEN]; + + int freq; + + struct nl_handle *nl_preq, *nl_mgmt; + struct nl_cb *nl_cb; + + struct nl80211_wiphy_data *wiphy_data; + struct dl_list wiphy_list; }; struct wpa_driver_nl80211_data { struct nl80211_global *global; struct dl_list list; - u8 addr[ETH_ALEN]; + struct dl_list wiphy_list; char phyname[32]; void *ctx; - struct netlink_data *netlink; - int ioctl_sock; /* socket for ioctl() use */ int ifindex; int if_removed; int if_disabled; + int ignore_if_down_event; struct rfkill_data *rfkill; struct wpa_driver_capa capa; int has_capability; @@ -139,42 +227,43 @@ struct wpa_driver_nl80211_data { int scan_complete_events; - struct nl_handle *nl_handle; - struct nl_handle *nl_handle_event; - struct nl_handle *nl_handle_preq; - struct nl_cache *nl_cache; - struct nl_cache *nl_cache_event; - struct nl_cache *nl_cache_preq; struct nl_cb *nl_cb; - struct genl_family *nl80211; u8 auth_bssid[ETH_ALEN]; u8 bssid[ETH_ALEN]; int associated; u8 ssid[32]; size_t ssid_len; - int nlmode; - int ap_scan_as_station; + enum nl80211_iftype nlmode; + enum nl80211_iftype ap_scan_as_station; unsigned int assoc_freq; int monitor_sock; int monitor_ifidx; - int no_monitor_iface_capab; - int disable_11b_rates; + int monitor_refcount; + unsigned int disabled_11b_rates:1; unsigned int pending_remain_on_chan:1; + unsigned int in_interface_list:1; + unsigned int device_ap_sme:1; + unsigned int poll_command_supported:1; + unsigned int data_tx_status:1; + unsigned int scan_for_auth:1; + unsigned int retry_auth:1; + unsigned int use_monitor:1; u64 remain_on_chan_cookie; u64 send_action_cookie; unsigned int last_mgmt_freq; - unsigned int ap_oper_freq; struct wpa_driver_scan_filter *filter_ssids; size_t num_filter_ssids; struct i802_bss first_bss; + int eapol_tx_sock; + #ifdef HOSTAPD int eapol_sock; /* socket for EAPOL frames */ @@ -185,12 +274,27 @@ struct wpa_driver_nl80211_data { int last_freq; int last_freq_ht; #endif /* HOSTAPD */ + + /* From failed authentication command */ + int auth_freq; + u8 auth_bssid_[ETH_ALEN]; + u8 auth_ssid[32]; + size_t auth_ssid_len; + int auth_alg; + u8 *auth_ie; + size_t auth_ie_len; + u8 auth_wep_key[4][16]; + size_t auth_wep_key_len[4]; + int auth_wep_tx_keyidx; + int auth_local_state_change; + int auth_p2p; }; static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx); -static int wpa_driver_nl80211_set_mode(void *priv, int mode); +static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, + enum nl80211_iftype nlmode); static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv); static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, @@ -198,22 +302,28 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, int local_state_change); static void nl80211_remove_monitor_interface( struct wpa_driver_nl80211_data *drv); -static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv, +static int nl80211_send_frame_cmd(struct i802_bss *bss, unsigned int freq, unsigned int wait, - const u8 *buf, size_t buf_len, u64 *cookie); + const u8 *buf, size_t buf_len, u64 *cookie, + int no_cck, int no_ack, int offchanok); static int wpa_driver_nl80211_probe_req_report(void *priv, int report); -#ifdef ANDROID_BRCM_P2P_PATCH +#ifdef ANDROID +static int android_pno_start(struct i802_bss *bss, + struct wpa_driver_scan_params *params); +static int android_pno_stop(struct i802_bss *bss); +#endif /* ANDROID */ +#ifdef ANDROID_P2P static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, enum wpa_event_type type, const u8 *frame, size_t len); -int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len); int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration); +int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len); int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow); int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, const struct wpabuf *proberesp, const struct wpabuf *assocresp); -#endif +#endif #ifdef HOSTAPD static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); @@ -222,12 +332,19 @@ static int wpa_driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type, const char *ifname); #else /* HOSTAPD */ -static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) +static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) +{ +} + +static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) +{ +} + +static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) { return 0; } #endif /* HOSTAPD */ - #ifdef ANDROID extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len); @@ -238,12 +355,36 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, int ifindex, int disabled); static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv); +static int wpa_driver_nl80211_authenticate_retry( + struct wpa_driver_nl80211_data *drv); + + +static int is_ap_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_AP || + nlmode == NL80211_IFTYPE_P2P_GO); +} + + +static int is_sta_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_STATION || + nlmode == NL80211_IFTYPE_P2P_CLIENT); +} + + +static int is_p2p_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_P2P_CLIENT || + nlmode == NL80211_IFTYPE_P2P_GO); +} struct nl80211_bss_info_arg { struct wpa_driver_nl80211_data *drv; struct wpa_scan_results *res; unsigned int assoc_freq; + u8 assoc_bssid[ETH_ALEN]; }; static int bss_info_handler(struct nl_msg *msg, void *arg); @@ -279,7 +420,7 @@ static int no_seq_check(struct nl_msg *msg, void *arg) } -static int send_and_recv(struct wpa_driver_nl80211_data *drv, +static int send_and_recv(struct nl80211_global *global, struct nl_handle *nl_handle, struct nl_msg *msg, int (*valid_handler)(struct nl_msg *, void *), void *valid_data) @@ -287,7 +428,7 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv, struct nl_cb *cb; int err = -ENOMEM; - cb = nl_cb_clone(drv->nl_cb); + cb = nl_cb_clone(global->nl_cb); if (!cb) goto out; @@ -314,13 +455,22 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv, } +static int send_and_recv_msgs_global(struct nl80211_global *global, + struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), + void *valid_data) +{ + return send_and_recv(global, global->nl, msg, valid_handler, + valid_data); +} + int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg, int (*valid_handler)(struct nl_msg *, void *), void *valid_data) { - return send_and_recv(drv, drv->nl_handle, msg, valid_handler, - valid_data); + return send_and_recv(drv->global, drv->global->nl, msg, + valid_handler, valid_data); } @@ -361,7 +511,7 @@ static int family_handler(struct nl_msg *msg, void *arg) } -static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv, +static int nl_get_multicast_id(struct nl80211_global *global, const char *family, const char *group) { struct nl_msg *msg; @@ -371,11 +521,11 @@ static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv, msg = nlmsg_alloc(); if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"), + genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"), 0, 0, CTRL_CMD_GETFAMILY, 0); NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family); - ret = send_and_recv_msgs(drv, msg, family_handler, &res); + ret = send_and_recv_msgs_global(global, msg, family_handler, &res); msg = NULL; if (ret == 0) ret = res.id; @@ -386,6 +536,235 @@ nla_put_failure: } +static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv, + struct nl_msg *msg, int flags, uint8_t cmd) +{ + return genlmsg_put(msg, 0, 0, drv->global->nl80211_id, + 0, flags, cmd, 0); +} + + +struct wiphy_idx_data { + int wiphy_idx; +}; + + +static int netdev_info_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wiphy_idx_data *info = arg; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_WIPHY]) + info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]); + + return NL_SKIP; +} + + +static int nl80211_get_wiphy_index(struct i802_bss *bss) +{ + struct nl_msg *msg; + struct wiphy_idx_data data = { + .wiphy_idx = -1, + }; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0) + return data.wiphy_idx; + msg = NULL; +nla_put_failure: + nlmsg_free(msg); + return -1; +} + + +static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv, + struct nl80211_wiphy_data *w) +{ + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS); + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx); + + ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Register beacons command " + "failed: ret=%d (%s)", + ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle) +{ + struct nl80211_wiphy_data *w = eloop_ctx; + + wpa_printf(MSG_DEBUG, "nl80211: Beacon event message available"); + + nl_recvmsgs(handle, w->nl_cb); +} + + +static int process_beacon_event(struct nl_msg *msg, void *arg) +{ + struct nl80211_wiphy_data *w = arg; + struct wpa_driver_nl80211_data *drv; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + union wpa_event_data event; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (gnlh->cmd != NL80211_CMD_FRAME) { + wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)", + gnlh->cmd); + return NL_SKIP; + } + + if (!tb[NL80211_ATTR_FRAME]) + return NL_SKIP; + + dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data, + wiphy_list) { + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]); + event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]); + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); + } + + return NL_SKIP; +} + + +static struct nl80211_wiphy_data * +nl80211_get_wiphy_data_ap(struct i802_bss *bss) +{ + static DEFINE_DL_LIST(nl80211_wiphys); + struct nl80211_wiphy_data *w; + int wiphy_idx, found = 0; + struct i802_bss *tmp_bss; + + if (bss->wiphy_data != NULL) + return bss->wiphy_data; + + wiphy_idx = nl80211_get_wiphy_index(bss); + + dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) { + if (w->wiphy_idx == wiphy_idx) + goto add; + } + + /* alloc new one */ + w = os_zalloc(sizeof(*w)); + if (w == NULL) + return NULL; + w->wiphy_idx = wiphy_idx; + dl_list_init(&w->bsss); + dl_list_init(&w->drvs); + + w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!w->nl_cb) { + os_free(w); + return NULL; + } + nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); + nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event, + w); + + w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb, + "wiphy beacons"); + if (w->nl_beacons == NULL) { + os_free(w); + return NULL; + } + + if (nl80211_register_beacons(bss->drv, w)) { + nl_destroy_handles(&w->nl_beacons); + os_free(w); + return NULL; + } + + eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons), + nl80211_recv_beacons, w, w->nl_beacons); + + dl_list_add(&nl80211_wiphys, &w->list); + +add: + /* drv entry for this bss already there? */ + dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) { + if (tmp_bss->drv == bss->drv) { + found = 1; + break; + } + } + /* if not add it */ + if (!found) + dl_list_add(&w->drvs, &bss->drv->wiphy_list); + + dl_list_add(&w->bsss, &bss->wiphy_list); + bss->wiphy_data = w; + return w; +} + + +static void nl80211_put_wiphy_data_ap(struct i802_bss *bss) +{ + struct nl80211_wiphy_data *w = bss->wiphy_data; + struct i802_bss *tmp_bss; + int found = 0; + + if (w == NULL) + return; + bss->wiphy_data = NULL; + dl_list_del(&bss->wiphy_list); + + /* still any for this drv present? */ + dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) { + if (tmp_bss->drv == bss->drv) { + found = 1; + break; + } + } + /* if not remove it */ + if (!found) + dl_list_del(&bss->drv->wiphy_list); + + if (!dl_list_empty(&w->bsss)) + return; + + eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons)); + + nl_cb_put(w->nl_cb); + nl_destroy_handles(&w->nl_beacons); + dl_list_del(&w->list); + os_free(w); +} + + static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid) { struct i802_bss *bss = priv; @@ -479,17 +858,33 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv, } +static struct wpa_driver_nl80211_data * +nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len) +{ + struct wpa_driver_nl80211_data *drv; + dl_list_for_each(drv, &global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) || + have_ifidx(drv, idx)) + return drv; + } + return NULL; +} + + static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len) { - struct wpa_driver_nl80211_data *drv = ctx; + struct nl80211_global *global = ctx; + struct wpa_driver_nl80211_data *drv; int attrlen, rta_len; struct rtattr *attr; u32 brid = 0; + char namebuf[IFNAMSIZ]; - if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) && - !have_ifidx(drv, ifi->ifi_index)) { + drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); + if (!drv) { wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign " "ifindex %d", ifi->ifi_index); return; @@ -504,15 +899,38 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { + if (if_indextoname(ifi->ifi_index, namebuf) && + linux_iface_up(drv->global->ioctl_sock, + drv->first_bss.ifname) > 0) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down " + "event since interface %s is up", namebuf); + return; + } wpa_printf(MSG_DEBUG, "nl80211: Interface down"); - drv->if_disabled = 1; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); + if (drv->ignore_if_down_event) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down " + "event generated by mode change"); + drv->ignore_if_down_event = 0; + } else { + drv->if_disabled = 1; + wpa_supplicant_event(drv->ctx, + EVENT_INTERFACE_DISABLED, NULL); + } } if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { - wpa_printf(MSG_DEBUG, "nl80211: Interface up"); - drv->if_disabled = 0; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); + if (if_indextoname(ifi->ifi_index, namebuf) && + linux_iface_up(drv->global->ioctl_sock, + drv->first_bss.ifname) == 0) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up " + "event since interface %s is down", + namebuf); + } else { + wpa_printf(MSG_DEBUG, "nl80211: Interface up"); + drv->if_disabled = 0; + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, + NULL); + } } /* @@ -524,7 +942,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, if (drv->operstate == 1 && (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && !(ifi->ifi_flags & IFF_RUNNING)) - netlink_send_oper_ifla(drv->netlink, drv->ifindex, + netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, IF_OPER_UP); attrlen = len; @@ -541,16 +959,13 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, attr = RTA_NEXT(attr, attrlen); } -#ifdef HOSTAPD if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been added to bridge */ - char namebuf[IFNAMSIZ]; if_indextoname(brid, namebuf); wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s", brid, namebuf); add_ifidx(drv, brid); } -#endif /* HOSTAPD */ } @@ -558,11 +973,19 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len) { - struct wpa_driver_nl80211_data *drv = ctx; + struct nl80211_global *global = ctx; + struct wpa_driver_nl80211_data *drv; int attrlen, rta_len; struct rtattr *attr; u32 brid = 0; + drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); + if (!drv) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for " + "foreign ifindex %d", ifi->ifi_index); + return; + } + attrlen = len; attr = (struct rtattr *) buf; @@ -578,7 +1001,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, attr = RTA_NEXT(attr, attrlen); } -#ifdef HOSTAPD if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been removed from bridge */ char namebuf[IFNAMSIZ]; @@ -587,7 +1009,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, "%s", brid, namebuf); del_ifidx(drv, brid); } -#endif /* HOSTAPD */ } @@ -629,8 +1050,7 @@ static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv) if (!msg) goto nla_put_failure; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP, - NL80211_CMD_GET_SCAN, 0); + nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); arg.drv = drv; @@ -656,12 +1076,12 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 status; -#ifdef ANDROID_BRCM_P2P_PATCH +#ifdef ANDROID_P2P struct wpa_supplicant *wpa_s = drv->ctx; #endif mgmt = (const struct ieee80211_mgmt *) frame; -#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_BRCM_P2P_PATCH) +#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_P2P) if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) { if (len < 24 + sizeof(mgmt->u.assoc_req)) { wpa_printf(MSG_DEBUG, "nl80211: Too short association event " @@ -674,7 +1094,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, event.assoc_info.req_ies_len = len - 24 - sizeof(mgmt->u.assoc_req); event.assoc_info.addr = mgmt->sa; } else { -#endif +#endif if (len < 24 + sizeof(mgmt->u.assoc_resp)) { wpa_printf(MSG_DEBUG, "nl80211: Too short association event " "frame"); @@ -708,7 +1128,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, } event.assoc_info.freq = drv->assoc_freq; -#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_BRCM_P2P_PATCH) +#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_P2P) } #endif wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); @@ -765,6 +1185,29 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, } +static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv, + struct nlattr *reason, struct nlattr *addr) +{ + union wpa_event_data data; + + if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { + /* + * Avoid reporting two disassociation events that could + * confuse the core code. + */ + wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect " + "event when using userspace SME"); + return; + } + + drv->associated = 0; + os_memset(&data, 0, sizeof(data)); + if (reason) + data.disassoc_info.reason_code = nla_get_u16(reason); + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data); +} + + static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv, enum nl80211_commands cmd, struct nlattr *addr) { @@ -819,7 +1262,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, event.rx_action.data = &mgmt->u.action.category + 1; event.rx_action.len = frame + len - event.rx_action.data; wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); -#ifdef ANDROID_BRCM_P2P_PATCH +#ifdef ANDROID_P2P } else if (stype == WLAN_FC_STYPE_ASSOC_REQ) { mlme_event_assoc(drv, frame, len); } else if (stype == WLAN_FC_STYPE_DISASSOC) { @@ -835,26 +1278,29 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, } -static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv, - struct nlattr *cookie, const u8 *frame, - size_t len, struct nlattr *ack) +static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv, + struct nlattr *cookie, const u8 *frame, + size_t len, struct nlattr *ack) { union wpa_event_data event; const struct ieee80211_hdr *hdr; u16 fc; - u64 cookie_val; - if (!cookie) - return; + if (!is_ap_interface(drv->nlmode)) { + u64 cookie_val; - cookie_val = nla_get_u64(cookie); - wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s " - "(ack=%d)", - (long long unsigned int) cookie_val, - cookie_val == drv->send_action_cookie ? - " (match)" : " (unknown)", ack != NULL); - if (cookie_val != drv->send_action_cookie) - return; + if (!cookie) + return; + + cookie_val = nla_get_u64(cookie); + wpa_printf(MSG_DEBUG, "nl80211: Action TX status:" + " cookie=0%llx%s (ack=%d)", + (long long unsigned int) cookie_val, + cookie_val == drv->send_action_cookie ? + " (match)" : " (unknown)", ack != NULL); + if (cookie_val != drv->send_action_cookie) + return; + } hdr = (const struct ieee80211_hdr *) frame; fc = le_to_host16(hdr->frame_control); @@ -906,7 +1352,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, reason_code = le_to_host16(mgmt->u.deauth.reason_code); if (type == EVENT_DISASSOC) { -#ifdef ANDROID_BRCM_P2P_PATCH +#ifdef ANDROID_P2P if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) { event.disassoc_info.addr = mgmt->sa; @@ -920,7 +1366,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, mgmt->u.disassoc.variable; } } else { -#ifdef ANDROID_BRCM_P2P_PATCH +#ifdef ANDROID_P2P if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) { event.deauth_info.addr = mgmt->sa; @@ -1011,8 +1457,8 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv, mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_FRAME_TX_STATUS: - mlme_event_action_tx_status(drv, cookie, nla_data(frame), - nla_len(frame), ack); + mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame), + nla_len(frame), ack); break; case NL80211_CMD_UNPROT_DEAUTHENTICATE: mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH, @@ -1117,7 +1563,8 @@ static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv, if (cookie != drv->remain_on_chan_cookie) return; /* not for us */ - drv->pending_remain_on_chan = !cancel_event; + if (cancel_event) + drv->pending_remain_on_chan = 0; os_memset(&data, 0, sizeof(data)); data.remain_on_channel.freq = freq; @@ -1139,6 +1586,14 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, int freqs[MAX_REPORT_FREQS]; int num_freqs = 0; + if (drv->scan_for_auth) { + drv->scan_for_auth = 0; + wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing " + "cfg80211 BSS entry"); + wpa_driver_nl80211_authenticate_retry(drv); + return; + } + os_memset(&event, 0, sizeof(event)); info = &event.scan_info; info->aborted = aborted; @@ -1228,14 +1683,14 @@ static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); return send_and_recv_msgs(drv, msg, get_link_signal, sig); nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -1296,13 +1751,88 @@ static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0); + nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); return send_and_recv_msgs(drv, msg, get_link_noise, sig_change); nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int get_noise_for_scan_results(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; + static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { + [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, + }; + struct wpa_scan_results *scan_results = arg; + struct wpa_scan_res *scan_res; + size_t i; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_SURVEY_INFO]) { + wpa_printf(MSG_DEBUG, "nl80211: Survey data missing"); + return NL_SKIP; + } + + if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, + tb[NL80211_ATTR_SURVEY_INFO], + survey_policy)) { + wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested " + "attributes"); + return NL_SKIP; + } + + if (!sinfo[NL80211_SURVEY_INFO_NOISE]) + return NL_SKIP; + + if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) + return NL_SKIP; + + for (i = 0; i < scan_results->num; ++i) { + scan_res = scan_results->res[i]; + if (!scan_res) + continue; + if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != + scan_res->freq) + continue; + if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID)) + continue; + scan_res->noise = (s8) + nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); + scan_res->flags &= ~WPA_SCAN_NOISE_INVALID; + } + + return NL_SKIP; +} + + +static int nl80211_get_noise_for_scan_results( + struct wpa_driver_nl80211_data *drv, + struct wpa_scan_results *scan_res) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, + scan_res); + nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -1385,8 +1915,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, addr = nla_data(tb[NL80211_ATTR_MAC]); wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr)); - if (drv->nlmode == NL80211_IFTYPE_AP && - drv->no_monitor_iface_capab) { + if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { u8 *ies = NULL; size_t ies_len = 0; if (tb[NL80211_ATTR_IE]) { @@ -1419,8 +1948,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR, MAC2STR(addr)); - if (drv->nlmode == NL80211_IFTYPE_AP && - drv->no_monitor_iface_capab) { + if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { drv_event_disassoc(drv->ctx, addr); return; } @@ -1434,38 +1962,138 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, } -static int process_event(struct nl_msg *msg, void *arg) +static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) { - struct wpa_driver_nl80211_data *drv = arg; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA]; + static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = { + [NL80211_REKEY_DATA_KEK] = { + .minlen = NL80211_KEK_LEN, + .maxlen = NL80211_KEK_LEN, + }, + [NL80211_REKEY_DATA_KCK] = { + .minlen = NL80211_KCK_LEN, + .maxlen = NL80211_KCK_LEN, + }, + [NL80211_REKEY_DATA_REPLAY_CTR] = { + .minlen = NL80211_REPLAY_CTR_LEN, + .maxlen = NL80211_REPLAY_CTR_LEN, + }, + }; union wpa_event_data data; - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); + if (!tb[NL80211_ATTR_MAC]) + return; + if (!tb[NL80211_ATTR_REKEY_DATA]) + return; + if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA, + tb[NL80211_ATTR_REKEY_DATA], rekey_policy)) + return; + if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]) + return; + + os_memset(&data, 0, sizeof(data)); + data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR, + MAC2STR(data.driver_gtk_rekey.bssid)); + data.driver_gtk_rekey.replay_ctr = + nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]); + wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter", + data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN); + wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data); +} + + +static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE]; + static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = { + [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 }, + [NL80211_PMKSA_CANDIDATE_BSSID] = { + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN, + }, + [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG }, + }; + union wpa_event_data data; + + if (!tb[NL80211_ATTR_PMKSA_CANDIDATE]) + return; + if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE, + tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy)) + return; + if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] || + !cand[NL80211_PMKSA_CANDIDATE_BSSID]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.pmkid_candidate.bssid, + nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN); + data.pmkid_candidate.index = + nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]); + data.pmkid_candidate.preauth = + cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL; + wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); +} - if (tb[NL80211_ATTR_IFINDEX]) { - int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); - if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) { - wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)" - " for foreign interface (ifindex %d)", - gnlh->cmd, ifindex); - return NL_SKIP; - } - } - if (drv->ap_scan_as_station && - (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS || - gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) { +static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + union wpa_event_data data; + + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.client_poll.addr, + nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + + wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data); +} + + +static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, + int wds) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + union wpa_event_data event; + + if (!tb[NL80211_ATTR_MAC]) + return; + + os_memset(&event, 0, sizeof(event)); + event.rx_from_unknown.bssid = bss->addr; + event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]); + event.rx_from_unknown.wds = wds; + + wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); +} + + +static void do_process_drv_event(struct wpa_driver_nl80211_data *drv, + int cmd, struct nlattr **tb) +{ + if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && + (cmd == NL80211_CMD_NEW_SCAN_RESULTS || + cmd == NL80211_CMD_SCAN_ABORTED)) { wpa_driver_nl80211_set_mode(&drv->first_bss, - IEEE80211_MODE_AP); - drv->ap_scan_as_station = 0; + drv->ap_scan_as_station); + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } - switch (gnlh->cmd) { + switch (cmd) { case NL80211_CMD_TRIGGER_SCAN: wpa_printf(MSG_DEBUG, "nl80211: Scan trigger"); break; + case NL80211_CMD_START_SCHED_SCAN: + wpa_printf(MSG_DEBUG, "nl80211: Sched scan started"); + break; + case NL80211_CMD_SCHED_SCAN_STOPPED: + wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped"); + wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL); + break; case NL80211_CMD_NEW_SCAN_RESULTS: wpa_printf(MSG_DEBUG, "nl80211: New scan results available"); drv->scan_complete_events = 1; @@ -1473,6 +2101,11 @@ static int process_event(struct nl_msg *msg, void *arg) drv->ctx); send_scan_event(drv, 0, tb); break; + case NL80211_CMD_SCHED_SCAN_RESULTS: + wpa_printf(MSG_DEBUG, + "nl80211: New sched scan results available"); + send_scan_event(drv, 0, tb); + break; case NL80211_CMD_SCAN_ABORTED: wpa_printf(MSG_DEBUG, "nl80211: Scan aborted"); /* @@ -1487,39 +2120,25 @@ static int process_event(struct nl_msg *msg, void *arg) case NL80211_CMD_ASSOCIATE: case NL80211_CMD_DEAUTHENTICATE: case NL80211_CMD_DISASSOCIATE: - case NL80211_CMD_FRAME: case NL80211_CMD_FRAME_TX_STATUS: case NL80211_CMD_UNPROT_DEAUTHENTICATE: case NL80211_CMD_UNPROT_DISASSOCIATE: - mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME], + mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE]); break; case NL80211_CMD_CONNECT: case NL80211_CMD_ROAM: - mlme_event_connect(drv, gnlh->cmd, + mlme_event_connect(drv, cmd, tb[NL80211_ATTR_STATUS_CODE], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_REQ_IE], tb[NL80211_ATTR_RESP_IE]); break; case NL80211_CMD_DISCONNECT: - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { - /* - * Avoid reporting two disassociation events that could - * confuse the core code. - */ - wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect " - "event when using userspace SME"); - break; - } - drv->associated = 0; - os_memset(&data, 0, sizeof(data)); - if (tb[NL80211_ATTR_REASON_CODE]) - data.disassoc_info.reason_code = - nla_get_u16(tb[NL80211_ATTR_REASON_CODE]); - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data); + mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], + tb[NL80211_ATTR_MAC]); break; case NL80211_CMD_MICHAEL_MIC_FAILURE: mlme_event_michael_mic_failure(drv, tb); @@ -1552,6 +2171,95 @@ static int process_event(struct nl_msg *msg, void *arg) case NL80211_CMD_DEL_STATION: nl80211_del_station_event(drv, tb); break; + case NL80211_CMD_SET_REKEY_OFFLOAD: + nl80211_rekey_offload_event(drv, tb); + break; + case NL80211_CMD_PMKSA_CANDIDATE: + nl80211_pmksa_candidate_event(drv, tb); + break; + case NL80211_CMD_PROBE_CLIENT: + nl80211_client_probe_event(drv, tb); + break; + default: + wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " + "(cmd=%d)", cmd); + break; + } +} + + +static int process_drv_event(struct nl_msg *msg, void *arg) +{ + struct wpa_driver_nl80211_data *drv = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_IFINDEX]) { + int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); + if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) { + wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)" + " for foreign interface (ifindex %d)", + gnlh->cmd, ifindex); + return NL_SKIP; + } + } + + do_process_drv_event(drv, gnlh->cmd, tb); + return NL_SKIP; +} + + +static int process_global_event(struct nl_msg *msg, void *arg) +{ + struct nl80211_global *global = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct wpa_driver_nl80211_data *drv; + int ifidx = -1; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_IFINDEX]) + ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); + + dl_list_for_each(drv, &global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (ifidx == -1 || ifidx == drv->ifindex || + have_ifidx(drv, ifidx)) + do_process_drv_event(drv, gnlh->cmd, tb); + } + + return NL_SKIP; +} + + +static int process_bss_event(struct nl_msg *msg, void *arg) +{ + struct i802_bss *bss = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + switch (gnlh->cmd) { + case NL80211_CMD_FRAME: + case NL80211_CMD_FRAME_TX_STATUS: + mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME], + tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], + tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], + tb[NL80211_ATTR_COOKIE]); + break; + case NL80211_CMD_UNEXPECTED_FRAME: + nl80211_spurious_frame(bss, tb, 0); + break; + case NL80211_CMD_UNEXPECTED_4ADDR_FRAME: + nl80211_spurious_frame(bss, tb, 1); + break; default: wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", gnlh->cmd); @@ -1565,18 +2273,11 @@ static int process_event(struct nl_msg *msg, void *arg) static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx, void *handle) { - struct nl_cb *cb; - struct wpa_driver_nl80211_data *drv = eloop_ctx; + struct nl_cb *cb = eloop_ctx; wpa_printf(MSG_DEBUG, "nl80211: Event message available"); - cb = nl_cb_clone(drv->nl_cb); - if (!cb) - return; - nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv); nl_recvmsgs(handle, cb); - nl_cb_put(cb); } @@ -1604,43 +2305,82 @@ static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg) alpha2[1] = alpha2_arg[1]; alpha2[2] = '\0'; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_REQ_SET_REG, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG); NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2); if (send_and_recv_msgs(drv, msg, NULL, NULL)) return -EINVAL; return 0; nla_put_failure: + nlmsg_free(msg); return -EINVAL; } struct wiphy_info_data { - int max_scan_ssids; - int ap_supported; - int p2p_supported; - int auth_supported; - int connect_supported; - int offchan_tx_supported; - int max_remain_on_chan; + struct wpa_driver_capa *capa; + + unsigned int error:1; + unsigned int device_ap_sme:1; + unsigned int poll_command_supported:1; + unsigned int data_tx_status:1; + unsigned int monitor_supported:1; }; +static unsigned int probe_resp_offload_support(int supp_protocols) +{ + unsigned int prot = 0; + + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS; + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2; + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P; + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING; + + return prot; +} + + static int wiphy_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct wiphy_info_data *info = arg; int p2p_go_supported = 0, p2p_client_supported = 0; + int p2p_concurrent = 0; + int auth_supported = 0, connect_supported = 0; + struct wpa_driver_capa *capa = info->capa; + static struct nla_policy + iface_combination_policy[NUM_NL80211_IFACE_COMB] = { + [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED }, + [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 }, + [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG }, + [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 }, + }, + iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = { + [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED }, + [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 }, + }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) - info->max_scan_ssids = + capa->max_scan_ssids = nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); + if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]) + capa->max_sched_scan_ssids = + nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]); + + if (tb[NL80211_ATTR_MAX_MATCH_SETS]) + capa->max_match_sets = + nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]); + if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) { struct nlattr *nl_mode; int i; @@ -1648,7 +2388,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) { switch (nla_type(nl_mode)) { case NL80211_IFTYPE_AP: - info->ap_supported = 1; + capa->flags |= WPA_DRIVER_FLAGS_AP; break; case NL80211_IFTYPE_P2P_GO: p2p_go_supported = 1; @@ -1656,11 +2396,69 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) case NL80211_IFTYPE_P2P_CLIENT: p2p_client_supported = 1; break; + case NL80211_IFTYPE_MONITOR: + info->monitor_supported = 1; + break; } } } - info->p2p_supported = p2p_go_supported && p2p_client_supported; + if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) { + struct nlattr *nl_combi; + int rem_combi; + + nla_for_each_nested(nl_combi, + tb[NL80211_ATTR_INTERFACE_COMBINATIONS], + rem_combi) { + struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB]; + struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT]; + struct nlattr *nl_limit, *nl_mode; + int err, rem_limit, rem_mode; + int combination_has_p2p = 0, combination_has_mgd = 0; + + err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB, + nl_combi, + iface_combination_policy); + if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] || + !tb_comb[NL80211_IFACE_COMB_MAXNUM] || + !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) + goto broken_combination; + + nla_for_each_nested(nl_limit, + tb_comb[NL80211_IFACE_COMB_LIMITS], + rem_limit) { + err = nla_parse_nested(tb_limit, + MAX_NL80211_IFACE_LIMIT, + nl_limit, + iface_limit_policy); + if (err || + !tb_limit[NL80211_IFACE_LIMIT_TYPES]) + goto broken_combination; + + nla_for_each_nested( + nl_mode, + tb_limit[NL80211_IFACE_LIMIT_TYPES], + rem_mode) { + int ift = nla_type(nl_mode); + if (ift == NL80211_IFTYPE_P2P_GO || + ift == NL80211_IFTYPE_P2P_CLIENT) + combination_has_p2p = 1; + if (ift == NL80211_IFTYPE_STATION) + combination_has_mgd = 1; + } + if (combination_has_p2p && combination_has_mgd) + break; + } + + if (combination_has_p2p && combination_has_mgd) { + p2p_concurrent = 1; + break; + } + +broken_combination: + ; + } + } if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) { struct nlattr *nl_cmd; @@ -1668,21 +2466,92 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) nla_for_each_nested(nl_cmd, tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) { - u32 cmd = nla_get_u32(nl_cmd); - if (cmd == NL80211_CMD_AUTHENTICATE) - info->auth_supported = 1; - else if (cmd == NL80211_CMD_CONNECT) - info->connect_supported = 1; + switch (nla_get_u32(nl_cmd)) { + case NL80211_CMD_AUTHENTICATE: + auth_supported = 1; + break; + case NL80211_CMD_CONNECT: + connect_supported = 1; + break; + case NL80211_CMD_START_SCHED_SCAN: + capa->sched_scan_supported = 1; + break; + case NL80211_CMD_PROBE_CLIENT: + info->poll_command_supported = 1; + break; + } } } - if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) - info->offchan_tx_supported = 1; + if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) { + wpa_printf(MSG_DEBUG, "nl80211: Using driver-based " + "off-channel TX"); + capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX; + } + + if (tb[NL80211_ATTR_ROAM_SUPPORT]) { + wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming"); + capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION; + } + + /* default to 5000 since early versions of mac80211 don't set it */ + capa->max_remain_on_chan = 5000; + + if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD]) + capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD; if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]) - info->max_remain_on_chan = + capa->max_remain_on_chan = nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]); + if (auth_supported) + capa->flags |= WPA_DRIVER_FLAGS_SME; + else if (!connect_supported) { + wpa_printf(MSG_INFO, "nl80211: Driver does not support " + "authentication/association or connect commands"); + info->error = 1; + } + + if (p2p_go_supported && p2p_client_supported) + capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; + if (p2p_concurrent) { + wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group " + "interface (driver advertised support)"); + capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; + capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; + } + + if (tb[NL80211_ATTR_TDLS_SUPPORT]) { + wpa_printf(MSG_DEBUG, "nl80211: TDLS supported"); + capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT; + + if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) { + wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup"); + capa->flags |= + WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP; + } + } + + if (tb[NL80211_ATTR_DEVICE_AP_SME]) + info->device_ap_sme = 1; + + if (tb[NL80211_ATTR_FEATURE_FLAGS]) { + u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]); + + if (flags & NL80211_FEATURE_SK_TX_STATUS) + info->data_tx_status = 1; + } + + if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) { + int protocols = + nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]); + wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response " + "offload in AP mode"); + capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD; + capa->probe_resp_offloads = + probe_resp_offload_support(protocols); + } + return NL_SKIP; } @@ -1693,16 +2562,13 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg; os_memset(info, 0, sizeof(*info)); - - /* default to 5000 since early versions of mac80211 don't set it */ - info->max_remain_on_chan = 5000; + info->capa = &drv->capa; msg = nlmsg_alloc(); if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex); @@ -1720,6 +2586,10 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) struct wiphy_info_data info; if (wpa_driver_nl80211_get_info(drv, &info)) return -1; + + if (info.error) + return -1; + drv->has_capability = 1; /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | @@ -1734,131 +2604,132 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; - drv->capa.max_scan_ssids = info.max_scan_ssids; - if (info.ap_supported) - drv->capa.flags |= WPA_DRIVER_FLAGS_AP; + drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES; + drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; + drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; + drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS; - if (info.auth_supported) - drv->capa.flags |= WPA_DRIVER_FLAGS_SME; - else if (!info.connect_supported) { - wpa_printf(MSG_INFO, "nl80211: Driver does not support " - "authentication/association or connect commands"); - return -1; - } + drv->device_ap_sme = info.device_ap_sme; + drv->poll_command_supported = info.poll_command_supported; + drv->data_tx_status = info.data_tx_status; - if (info.offchan_tx_supported) { - wpa_printf(MSG_DEBUG, "nl80211: Using driver-based " - "off-channel TX"); - drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX; + /* + * If poll command is supported mac80211 is new enough to + * have everything we need to not need monitor interfaces. + */ + drv->use_monitor = !info.poll_command_supported; + + if (drv->device_ap_sme && drv->use_monitor) { + /* + * Non-mac80211 drivers may not support monitor interface. + * Make sure we do not get stuck with incorrect capability here + * by explicitly testing this. + */ + if (!info.monitor_supported) { + wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor " + "with device_ap_sme since no monitor mode " + "support detected"); + drv->use_monitor = 0; + } } - drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES; - drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; - if (info.p2p_supported) - drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; - drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; - drv->capa.max_remain_on_chan = info.max_remain_on_chan; + /* + * If we aren't going to use monitor interfaces, but the + * driver doesn't support data TX status, we won't get TX + * status for EAPOL frames. + */ + if (!drv->use_monitor && !info.data_tx_status) + drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; return 0; } -static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv) +#ifdef ANDROID +static int android_genl_ctrl_resolve(struct nl_handle *handle, + const char *name) { - int ret; - - /* Initialize generic netlink and nl80211 */ + /* + * Android ICS has very minimal genl_ctrl_resolve() implementation, so + * need to work around that. + */ + struct nl_cache *cache = NULL; + struct genl_family *nl80211 = NULL; + int id = -1; - drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (drv->nl_cb == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " - "callbacks"); - goto err1; + if (genl_ctrl_alloc_cache(handle, &cache) < 0) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " + "netlink cache"); + goto fail; } - drv->nl_handle = nl80211_handle_alloc(drv->nl_cb); - if (drv->nl_handle == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " - "callbacks"); - goto err2; - } + nl80211 = genl_ctrl_search_by_name(cache, name); + if (nl80211 == NULL) + goto fail; - drv->nl_handle_event = nl80211_handle_alloc(drv->nl_cb); - if (drv->nl_handle_event == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " - "callbacks (event)"); - goto err2b; - } + id = genl_family_get_id(nl80211); - if (genl_connect(drv->nl_handle)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " - "netlink"); - goto err3; - } +fail: + if (nl80211) + genl_family_put(nl80211); + if (cache) + nl_cache_free(cache); - if (genl_connect(drv->nl_handle_event)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " - "netlink (event)"); - goto err3; - } + return id; +} +#define genl_ctrl_resolve android_genl_ctrl_resolve +#endif /* ANDROID */ -#ifdef CONFIG_LIBNL20 - if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache"); - goto err3; - } - if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) < - 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache (event)"); - goto err3b; - } -#else /* CONFIG_LIBNL20 */ - drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle); - if (drv->nl_cache == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache"); - goto err3; - } - drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event); - if (drv->nl_cache_event == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache (event)"); - goto err3b; + +static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) +{ + int ret; + + global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (global->nl_cb == NULL) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " + "callbacks"); + return -1; } -#endif /* CONFIG_LIBNL20 */ - drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211"); - if (drv->nl80211 == NULL) { + global->nl = nl_create_handle(global->nl_cb, "nl"); + if (global->nl == NULL) + goto err; + + global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211"); + if (global->nl80211_id < 0) { wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not " "found"); - goto err4; + goto err; } - ret = nl_get_multicast_id(drv, "nl80211", "scan"); + global->nl_event = nl_create_handle(global->nl_cb, "event"); + if (global->nl_event == NULL) + goto err; + + ret = nl_get_multicast_id(global, "nl80211", "scan"); if (ret >= 0) - ret = nl_socket_add_membership(drv->nl_handle_event, ret); + ret = nl_socket_add_membership(global->nl_event, ret); if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " "membership for scan events: %d (%s)", ret, strerror(-ret)); - goto err4; + goto err; } - ret = nl_get_multicast_id(drv, "nl80211", "mlme"); + ret = nl_get_multicast_id(global, "nl80211", "mlme"); if (ret >= 0) - ret = nl_socket_add_membership(drv->nl_handle_event, ret); + ret = nl_socket_add_membership(global->nl_event, ret); if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " "membership for mlme events: %d (%s)", ret, strerror(-ret)); - goto err4; + goto err; } - ret = nl_get_multicast_id(drv, "nl80211", "regulatory"); + ret = nl_get_multicast_id(global, "nl80211", "regulatory"); if (ret >= 0) - ret = nl_socket_add_membership(drv->nl_handle_event, ret); + ret = nl_socket_add_membership(global->nl_event, ret); if (ret < 0) { wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast " "membership for regulatory events: %d (%s)", @@ -1866,27 +2737,43 @@ static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv) /* Continue without regulatory events */ } - eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event), - wpa_driver_nl80211_event_receive, drv, - drv->nl_handle_event); + nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, + process_global_event, global); + + eloop_register_read_sock(nl_socket_get_fd(global->nl_event), + wpa_driver_nl80211_event_receive, + global->nl_cb, global->nl_event); return 0; -err4: - nl_cache_free(drv->nl_cache_event); -err3b: - nl_cache_free(drv->nl_cache); -err3: - nl80211_handle_destroy(drv->nl_handle_event); -err2b: - nl80211_handle_destroy(drv->nl_handle); -err2: - nl_cb_put(drv->nl_cb); -err1: +err: + nl_destroy_handles(&global->nl_event); + nl_destroy_handles(&global->nl); + nl_cb_put(global->nl_cb); + global->nl_cb = NULL; return -1; } +static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv) +{ + drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!drv->nl_cb) { + wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct"); + return -1; + } + + nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, + process_drv_event, drv); + + return 0; +} + + static void wpa_driver_nl80211_rfkill_blocked(void *ctx) { wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked"); @@ -1901,7 +2788,8 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) { struct wpa_driver_nl80211_data *drv = ctx; wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked"); - if (linux_set_iface_flags(drv->ioctl_sock, drv->first_bss.ifname, 1)) { + if (linux_set_iface_flags(drv->global->ioctl_sock, + drv->first_bss.ifname, 1)) { wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP " "after rfkill unblock"); return; @@ -1943,6 +2831,90 @@ static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv) } +static void wpa_driver_nl80211_handle_eapol_tx_status(int sock, + void *eloop_ctx, + void *handle) +{ + struct wpa_driver_nl80211_data *drv = eloop_ctx; + u8 data[2048]; + struct msghdr msg; + struct iovec entry; + struct { + struct cmsghdr cm; + char control[512]; + } control; + struct cmsghdr *cmsg; + int res, found_ee = 0, found_wifi = 0, acked = 0; + union wpa_event_data event; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &entry; + msg.msg_iovlen = 1; + entry.iov_base = data; + entry.iov_len = sizeof(data); + msg.msg_control = &control; + msg.msg_controllen = sizeof(control); + + res = recvmsg(sock, &msg, MSG_ERRQUEUE); + /* if error or not fitting 802.3 header, return */ + if (res < 14) + return; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_WIFI_STATUS) { + int *ack; + + found_wifi = 1; + ack = (void *)CMSG_DATA(cmsg); + acked = *ack; + } + + if (cmsg->cmsg_level == SOL_PACKET && + cmsg->cmsg_type == PACKET_TX_TIMESTAMP) { + struct sock_extended_err *err = + (struct sock_extended_err *)CMSG_DATA(cmsg); + + if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS) + found_ee = 1; + } + } + + if (!found_ee || !found_wifi) + return; + + memset(&event, 0, sizeof(event)); + event.eapol_tx_status.dst = data; + event.eapol_tx_status.data = data + 14; + event.eapol_tx_status.data_len = res - 14; + event.eapol_tx_status.ack = acked; + wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event); +} + + +static int nl80211_init_bss(struct i802_bss *bss) +{ + bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!bss->nl_cb) + return -1; + + nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, + process_bss_event, bss); + + return 0; +} + + +static void nl80211_destroy_bss(struct i802_bss *bss) +{ + nl_cb_put(bss->nl_cb); + bss->nl_cb = NULL; +} + + /** * wpa_driver_nl80211_init - Initialize nl80211 driver interface * @ctx: context to be used when calling wpa_supplicant functions, @@ -1955,10 +2927,11 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, void *global_priv) { struct wpa_driver_nl80211_data *drv; - struct netlink_config *cfg; struct rfkill_config *rcfg; struct i802_bss *bss; + if (global_priv == NULL) + return NULL; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) return NULL; @@ -1969,32 +2942,18 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname)); drv->monitor_ifidx = -1; drv->monitor_sock = -1; - drv->ioctl_sock = -1; + drv->eapol_tx_sock = -1; + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; if (wpa_driver_nl80211_init_nl(drv)) { os_free(drv); return NULL; } - nl80211_get_phy_name(drv); - - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket(PF_INET,SOCK_DGRAM)"); + if (nl80211_init_bss(bss)) goto failed; - } - cfg = os_zalloc(sizeof(*cfg)); - if (cfg == NULL) - goto failed; - cfg->ctx = drv; - cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink; - cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink; - drv->netlink = netlink_init(cfg); - if (drv->netlink == NULL) { - os_free(cfg); - goto failed; - } + nl80211_get_phy_name(drv); rcfg = os_zalloc(sizeof(*rcfg)); if (rcfg == NULL) @@ -2012,32 +2971,46 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, if (wpa_driver_nl80211_finish_drv_init(drv)) goto failed; - if (drv->global) + drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0); + if (drv->eapol_tx_sock < 0) + goto failed; + + if (drv->data_tx_status) { + int enabled = 1; + + if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS, + &enabled, sizeof(enabled)) < 0) { + wpa_printf(MSG_DEBUG, + "nl80211: wifi status sockopt failed\n"); + drv->data_tx_status = 0; + if (!drv->use_monitor) + drv->capa.flags &= + ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; + } else { + eloop_register_read_sock(drv->eapol_tx_sock, + wpa_driver_nl80211_handle_eapol_tx_status, + drv, NULL); + } + } + + if (drv->global) { dl_list_add(&drv->global->interfaces, &drv->list); + drv->in_interface_list = 1; + } return bss; failed: - rfkill_deinit(drv->rfkill); - netlink_deinit(drv->netlink); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - - genl_family_put(drv->nl80211); - nl_cache_free(drv->nl_cache); - nl80211_handle_destroy(drv->nl_handle); - nl_cb_put(drv->nl_cb); - eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); - - os_free(drv); + wpa_driver_nl80211_deinit(bss); return NULL; } -static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv, +static int nl80211_register_frame(struct i802_bss *bss, struct nl_handle *nl_handle, u16 type, const u8 *match, size_t match_len) { + struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; int ret = -1; @@ -2045,14 +3018,18 @@ static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_REGISTER_ACTION, 0); + wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p", + type, nl_handle); + wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match", + match, match_len); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type); NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match); - ret = send_and_recv(drv, nl_handle, msg, NULL, NULL); + ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Register frame command " @@ -2069,58 +3046,213 @@ nla_put_failure: } -static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv, +static int nl80211_alloc_mgmt_handle(struct i802_bss *bss) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + + if (bss->nl_mgmt) { + wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting " + "already on! (nl_mgmt=%p)", bss->nl_mgmt); + return -1; + } + + bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt"); + if (bss->nl_mgmt == NULL) + return -1; + + eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt), + wpa_driver_nl80211_event_receive, bss->nl_cb, + bss->nl_mgmt); + + return 0; +} + + +static int nl80211_register_action_frame(struct i802_bss *bss, const u8 *match, size_t match_len) { u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4); - return nl80211_register_frame(drv, drv->nl_handle_event, + return nl80211_register_frame(bss, bss->nl_mgmt, type, match, match_len); } -static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv) +static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) { -#ifdef CONFIG_P2P + struct wpa_driver_nl80211_data *drv = bss->drv; + + if (nl80211_alloc_mgmt_handle(bss)) + return -1; + wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP " + "handle %p", bss->nl_mgmt); + +#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) /* GAS Initial Request */ - if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0a", 2) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0) return -1; /* GAS Initial Response */ - if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0b", 2) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0) return -1; /* GAS Comeback Request */ - if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0c", 2) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0) return -1; /* GAS Comeback Response */ - if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0d", 2) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0) return -1; +#endif /* CONFIG_P2P || CONFIG_INTERWORKING */ +#ifdef CONFIG_P2P /* P2P Public Action */ - if (nl80211_register_action_frame(drv, + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x09\x50\x6f\x9a\x09", 6) < 0) return -1; /* P2P Action */ - if (nl80211_register_action_frame(drv, + if (nl80211_register_action_frame(bss, (u8 *) "\x7f\x50\x6f\x9a\x09", 5) < 0) return -1; #endif /* CONFIG_P2P */ #ifdef CONFIG_IEEE80211W /* SA Query Response */ - if (nl80211_register_action_frame(drv, (u8 *) "\x08\x01", 2) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0) return -1; #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_TDLS + if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) { + /* TDLS Discovery Response */ + if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) < + 0) + return -1; + } +#endif /* CONFIG_TDLS */ /* FT Action frames */ - if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0) + if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0) return -1; else drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT | WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; + /* WNM - BSS Transition Management Request */ + if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0) + return -1; + return 0; } +static int nl80211_register_spurious_class3(struct i802_bss *bss) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 " + "failed: ret=%d (%s)", + ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss) +{ + static const int stypes[] = { + WLAN_FC_STYPE_AUTH, + WLAN_FC_STYPE_ASSOC_REQ, + WLAN_FC_STYPE_REASSOC_REQ, + WLAN_FC_STYPE_DISASSOC, + WLAN_FC_STYPE_DEAUTH, + WLAN_FC_STYPE_ACTION, + WLAN_FC_STYPE_PROBE_REQ, +/* Beacon doesn't work as mac80211 doesn't currently allow + * it, but it wouldn't really be the right thing anyway as + * it isn't per interface ... maybe just dump the scan + * results periodically for OLBC? + */ +// WLAN_FC_STYPE_BEACON, + }; + unsigned int i; + + if (nl80211_alloc_mgmt_handle(bss)) + return -1; + wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP " + "handle %p", bss->nl_mgmt); + + for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) { + if (nl80211_register_frame(bss, bss->nl_mgmt, + (WLAN_FC_TYPE_MGMT << 2) | + (stypes[i] << 4), + NULL, 0) < 0) { + goto out_err; + } + } + + if (nl80211_register_spurious_class3(bss)) + goto out_err; + + if (nl80211_get_wiphy_data_ap(bss) == NULL) + goto out_err; + + return 0; + +out_err: + eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt)); + nl_destroy_handles(&bss->nl_mgmt); + return -1; +} + + +static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss) +{ + if (nl80211_alloc_mgmt_handle(bss)) + return -1; + wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP " + "handle %p (device SME)", bss->nl_mgmt); + + if (nl80211_register_frame(bss, bss->nl_mgmt, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_ACTION << 4), + NULL, 0) < 0) + goto out_err; + + return 0; + +out_err: + eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt)); + nl_destroy_handles(&bss->nl_mgmt); + return -1; +} + + +static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason) +{ + if (bss->nl_mgmt == NULL) + return; + wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p " + "(%s)", bss->nl_mgmt, reason); + eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt)); + nl_destroy_handles(&bss->nl_mgmt); + + nl80211_put_wiphy_data_ap(bss); +} + + static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx) { wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); @@ -2137,12 +3269,19 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) drv->first_bss.ifindex = drv->ifindex; #ifndef HOSTAPD - if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) { - wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to " + /* + * Make sure the interface starts up in station mode unless this is a + * dynamically added interface (e.g., P2P) that was already configured + * with proper iftype. + */ + if (drv->ifindex != drv->global->if_add_ifindex && + wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) { + wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to " "use managed mode"); + return -1; } - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) { + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { if (rfkill_is_blocked(drv->rfkill)) { wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable " "interface '%s' due to rfkill", @@ -2156,26 +3295,17 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) } } - netlink_send_oper_ifla(drv->netlink, drv->ifindex, + netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 1, IF_OPER_DORMANT); #endif /* HOSTAPD */ if (wpa_driver_nl80211_capa(drv)) return -1; - if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, drv->addr)) + if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + bss->addr)) return -1; - if (nl80211_register_action_frames(drv) < 0) { - wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action " - "frame processing - ignore for now"); - /* - * Older kernel versions did not support this, so ignore the - * error for now. Some functionality may not be available - * because of this. - */ - } - if (send_rfkill_event) { eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill, drv, drv->ctx); @@ -2193,12 +3323,12 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv) if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_BEACON, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -2215,17 +3345,22 @@ static void wpa_driver_nl80211_deinit(void *priv) struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - if (drv->nl_handle_preq) + if (drv->data_tx_status) + eloop_unregister_read_sock(drv->eapol_tx_sock); + if (drv->eapol_tx_sock >= 0) + close(drv->eapol_tx_sock); + + if (bss->nl_preq) wpa_driver_nl80211_probe_req_report(bss, 0); if (bss->added_if_into_bridge) { - if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname) - < 0) + if (linux_br_del_if(drv->global->ioctl_sock, bss->brname, + bss->ifname) < 0) wpa_printf(MSG_INFO, "nl80211: Failed to remove " "interface %s from bridge %s: %s", bss->ifname, bss->brname, strerror(errno)); } if (bss->added_bridge) { - if (linux_br_del(drv->ioctl_sock, bss->brname) < 0) + if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0) wpa_printf(MSG_INFO, "nl80211: Failed to remove " "bridge %s: %s", bss->brname, strerror(errno)); @@ -2233,7 +3368,7 @@ static void wpa_driver_nl80211_deinit(void *priv) nl80211_remove_monitor_interface(drv); - if (drv->nlmode == NL80211_IFTYPE_AP) + if (is_ap_interface(drv->nlmode)) wpa_driver_nl80211_del_beacon(drv); #ifdef HOSTAPD @@ -2254,32 +3389,28 @@ static void wpa_driver_nl80211_deinit(void *priv) os_free(drv->if_indices); #endif /* HOSTAPD */ - if (drv->disable_11b_rates) + if (drv->disabled_11b_rates) nl80211_disable_11b_rates(drv, drv->ifindex, 0); - netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); - netlink_deinit(drv->netlink); + netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0, + IF_OPER_UP); rfkill_deinit(drv->rfkill); eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); - (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0); - wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA); - - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); + (void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); + wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION); + nl80211_mgmt_unsubscribe(bss, "deinit"); - eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); - genl_family_put(drv->nl80211); - nl_cache_free(drv->nl_cache); - nl_cache_free(drv->nl_cache_event); - nl80211_handle_destroy(drv->nl_handle); - nl80211_handle_destroy(drv->nl_handle_event); nl_cb_put(drv->nl_cb); + nl80211_destroy_bss(&drv->first_bss); + os_free(drv->filter_ssids); - if (drv->global) + os_free(drv->auth_ie); + + if (drv->in_interface_list) dl_list_del(&drv->list); os_free(drv); @@ -2297,10 +3428,10 @@ static void wpa_driver_nl80211_deinit(void *priv) static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_nl80211_data *drv = eloop_ctx; - if (drv->ap_scan_as_station) { + if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) { wpa_driver_nl80211_set_mode(&drv->first_bss, - IEEE80211_MODE_AP); - drv->ap_scan_as_station = 0; + drv->ap_scan_as_station); + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); @@ -2319,16 +3450,20 @@ static int wpa_driver_nl80211_scan(void *priv, struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; int ret = 0, timeout; - struct nl_msg *msg, *ssids, *freqs; + struct nl_msg *msg, *ssids, *freqs, *rates; size_t i; + drv->scan_for_auth = 0; + msg = nlmsg_alloc(); ssids = nlmsg_alloc(); freqs = nlmsg_alloc(); - if (!msg || !ssids || !freqs) { + rates = nlmsg_alloc(); + if (!msg || !ssids || !freqs || !rates) { nlmsg_free(msg); nlmsg_free(ssids); nlmsg_free(freqs); + nlmsg_free(rates); return -1; } @@ -2337,8 +3472,7 @@ static int wpa_driver_nl80211_scan(void *priv, params->filter_ssids = NULL; drv->num_filter_ssids = params->num_filter_ssids; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_TRIGGER_SCAN, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); @@ -2353,8 +3487,8 @@ static int wpa_driver_nl80211_scan(void *priv, nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); if (params->extra_ies) { - wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs", - params->extra_ies, params->extra_ies_len); + wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs", + params->extra_ies, params->extra_ies_len); NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len, params->extra_ies); } @@ -2368,29 +3502,42 @@ static int wpa_driver_nl80211_scan(void *priv, nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); } + if (params->p2p_probe) { + /* + * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates + * by masking out everything else apart from the OFDM rates 6, + * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz + * rates are left enabled. + */ + NLA_PUT(rates, NL80211_BAND_2GHZ, 8, + "\x0c\x12\x18\x24\x30\x48\x60\x6c"); + nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates); + + NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE); + } + ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d " "(%s)", ret, strerror(-ret)); #ifdef HOSTAPD - if (drv->nlmode == NL80211_IFTYPE_AP) { + if (is_ap_interface(drv->nlmode)) { /* * mac80211 does not allow scan requests in AP mode, so * try to do this in station mode. */ - if (wpa_driver_nl80211_set_mode(bss, - IEEE80211_MODE_INFRA)) + if (wpa_driver_nl80211_set_mode( + bss, NL80211_IFTYPE_STATION)) goto nla_put_failure; if (wpa_driver_nl80211_scan(drv, params)) { - wpa_driver_nl80211_set_mode(bss, - IEEE80211_MODE_AP); + wpa_driver_nl80211_set_mode(bss, drv->nlmode); goto nla_put_failure; } /* Restore AP mode when processing scan results */ - drv->ap_scan_as_station = 1; + drv->ap_scan_as_station = drv->nlmode; ret = 0; } else goto nla_put_failure; @@ -2420,6 +3567,165 @@ nla_put_failure: nlmsg_free(ssids); nlmsg_free(msg); nlmsg_free(freqs); + nlmsg_free(rates); + return ret; +} + + +/** + * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan + * @priv: Pointer to private driver data from wpa_driver_nl80211_init() + * @params: Scan parameters + * @interval: Interval between scan cycles in milliseconds + * Returns: 0 on success, -1 on failure or if not supported + */ +static int wpa_driver_nl80211_sched_scan(void *priv, + struct wpa_driver_scan_params *params, + u32 interval) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ret = 0; + struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets; + size_t i; + +#ifdef ANDROID + if (!drv->capa.sched_scan_supported) + return android_pno_start(bss, params); +#endif /* ANDROID */ + + msg = nlmsg_alloc(); + ssids = nlmsg_alloc(); + freqs = nlmsg_alloc(); + if (!msg || !ssids || !freqs) { + nlmsg_free(msg); + nlmsg_free(ssids); + nlmsg_free(freqs); + return -1; + } + + os_free(drv->filter_ssids); + drv->filter_ssids = params->filter_ssids; + params->filter_ssids = NULL; + drv->num_filter_ssids = params->num_filter_ssids; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval); + + if (drv->num_filter_ssids && + (int) drv->num_filter_ssids <= drv->capa.max_match_sets) { + match_sets = nlmsg_alloc(); + + for (i = 0; i < drv->num_filter_ssids; i++) { + wpa_hexdump_ascii(MSG_MSGDUMP, + "nl80211: Sched scan filter SSID", + drv->filter_ssids[i].ssid, + drv->filter_ssids[i].ssid_len); + + match_set_ssid = nlmsg_alloc(); + nla_put(match_set_ssid, + NL80211_ATTR_SCHED_SCAN_MATCH_SSID, + drv->filter_ssids[i].ssid_len, + drv->filter_ssids[i].ssid); + + nla_put_nested(match_sets, i + 1, match_set_ssid); + + nlmsg_free(match_set_ssid); + } + + nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH, + match_sets); + nlmsg_free(match_sets); + } + + for (i = 0; i < params->num_ssids; i++) { + wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID", + params->ssids[i].ssid, + params->ssids[i].ssid_len); + NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len, + params->ssids[i].ssid); + } + if (params->num_ssids) + nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); + + if (params->extra_ies) { + wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs", + params->extra_ies, params->extra_ies_len); + NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len, + params->extra_ies); + } + + if (params->freqs) { + for (i = 0; params->freqs[i]; i++) { + wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u " + "MHz", params->freqs[i]); + NLA_PUT_U32(freqs, i + 1, params->freqs[i]); + } + nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + + /* TODO: if we get an error here, we should fall back to normal scan */ + + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: " + "ret=%d (%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + + wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - " + "scan interval %d msec", ret, interval); + +nla_put_failure: + nlmsg_free(ssids); + nlmsg_free(msg); + nlmsg_free(freqs); + return ret; +} + + +/** + * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan + * @priv: Pointer to private driver data from wpa_driver_nl80211_init() + * Returns: 0 on success, -1 on failure or if not supported + */ +static int wpa_driver_nl80211_stop_sched_scan(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ret = 0; + struct nl_msg *msg; + +#ifdef ANDROID + if (!drv->capa.sched_scan_supported) + return android_pno_stop(bss); +#endif /* ANDROID */ + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: " + "ret=%d (%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + + wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret); + +nla_put_failure: + nlmsg_free(msg); return ret; } @@ -2514,6 +3820,13 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz", _arg->assoc_freq); } + if (status == NL80211_BSS_STATUS_ASSOCIATED && + bss[NL80211_BSS_BSSID]) { + os_memcpy(_arg->assoc_bssid, + nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); + wpa_printf(MSG_DEBUG, "nl80211: Associated with " + MACSTR, MAC2STR(_arg->assoc_bssid)); + } } if (!res) return NL_SKIP; @@ -2555,7 +3868,7 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID; } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) { r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); - r->flags |= WPA_SCAN_LEVEL_INVALID; + r->flags |= WPA_SCAN_QUAL_INVALID; } else r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; if (bss[NL80211_BSS_TSF]) @@ -2657,7 +3970,7 @@ static void wpa_driver_nl80211_check_bss_status( "indicates BSS status with " MACSTR " as authenticated", MAC2STR(r->bssid)); - if (drv->nlmode == NL80211_IFTYPE_STATION && + if (is_sta_interface(drv->nlmode) && os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 && os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) != 0) { @@ -2675,13 +3988,13 @@ static void wpa_driver_nl80211_check_bss_status( "indicate BSS status with " MACSTR " as associated", MAC2STR(r->bssid)); - if (drv->nlmode == NL80211_IFTYPE_STATION && + if (is_sta_interface(drv->nlmode) && !drv->associated) { wpa_printf(MSG_DEBUG, "nl80211: Local state " "(not associated) does not match " "with BSS state"); clear_state_mismatch(drv, r->bssid); - } else if (drv->nlmode == NL80211_IFTYPE_STATION && + } else if (is_sta_interface(drv->nlmode) && os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "nl80211: Local state " @@ -2696,20 +4009,6 @@ static void wpa_driver_nl80211_check_bss_status( } -static void wpa_scan_results_free(struct wpa_scan_results *res) -{ - size_t i; - - if (res == NULL) - return; - - for (i = 0; i < res->num; i++) - os_free(res->res[i]); - os_free(res->res); - os_free(res); -} - - static struct wpa_scan_results * nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) { @@ -2725,8 +4024,7 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) if (!msg) goto nla_put_failure; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP, - NL80211_CMD_GET_SCAN, 0); + nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); arg.drv = drv; @@ -2734,8 +4032,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); msg = NULL; if (ret == 0) { - wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)", - (unsigned long) res->num); + wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu " + "BSSes)", (unsigned long) res->num); + nl80211_get_noise_for_scan_results(drv, res); return res; } wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d " @@ -2806,17 +4105,19 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, "set_tx=%d seq_len=%lu key_len=%lu", __func__, ifindex, alg, addr, key_idx, set_tx, (unsigned long) seq_len, (unsigned long) key_len); +#ifdef CONFIG_TDLS + if (key_idx == -1) + key_idx = 0; +#endif /* CONFIG_TDLS */ msg = nlmsg_alloc(); if (!msg) return -ENOMEM; if (alg == WPA_ALG_NONE) { - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_KEY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY); } else { - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_KEY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY); NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); switch (alg) { case WPA_ALG_WEP: @@ -2889,7 +4190,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, */ if (ret || !set_tx || alg == WPA_ALG_NONE) return ret; - if (drv->nlmode == NL80211_IFTYPE_AP && addr && + if (is_ap_interface(drv->nlmode) && addr && !is_broadcast_ether_addr(addr)) return ret; @@ -2897,8 +4198,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_KEY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY); NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); if (alg == WPA_ALG_IGTK) @@ -2940,6 +4240,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, return ret; nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -3069,7 +4370,7 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0); + nl80211_cmd(drv, msg, 0, cmd); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code); @@ -3080,8 +4381,9 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " - "(%s)", ret, strerror(-ret)); + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: MLME command failed: reason=%u ret=%d (%s)", + reason_code, ret, strerror(-ret)); goto nla_put_failure; } ret = 0; @@ -3134,6 +4436,52 @@ static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr, } +static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv, + struct wpa_driver_auth_params *params) +{ + int i; + + drv->auth_freq = params->freq; + drv->auth_alg = params->auth_alg; + drv->auth_wep_tx_keyidx = params->wep_tx_keyidx; + drv->auth_local_state_change = params->local_state_change; + drv->auth_p2p = params->p2p; + + if (params->bssid) + os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN); + else + os_memset(drv->auth_bssid_, 0, ETH_ALEN); + + if (params->ssid) { + os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len); + drv->auth_ssid_len = params->ssid_len; + } else + drv->auth_ssid_len = 0; + + + os_free(drv->auth_ie); + drv->auth_ie = NULL; + drv->auth_ie_len = 0; + if (params->ie) { + drv->auth_ie = os_malloc(params->ie_len); + if (drv->auth_ie) { + os_memcpy(drv->auth_ie, params->ie, params->ie_len); + drv->auth_ie_len = params->ie_len; + } + } + + for (i = 0; i < 4; i++) { + if (params->wep_key[i] && params->wep_key_len[i] && + params->wep_key_len[i] <= 16) { + os_memcpy(drv->auth_wep_key[i], params->wep_key[i], + params->wep_key_len[i]); + drv->auth_wep_key_len[i] = params->wep_key_len[i]; + } else + drv->auth_wep_key_len[i] = 0; + } +} + + static int wpa_driver_nl80211_authenticate( void *priv, struct wpa_driver_auth_params *params) { @@ -3142,13 +4490,20 @@ static int wpa_driver_nl80211_authenticate( int ret = -1, i; struct nl_msg *msg; enum nl80211_auth_type type; + enum nl80211_iftype nlmode; int count = 0; + int is_retry; + + is_retry = drv->retry_auth; + drv->retry_auth = 0; drv->associated = 0; os_memset(drv->auth_bssid, 0, ETH_ALEN); /* FIX: IBSS mode */ - if (drv->nlmode != NL80211_IFTYPE_STATION && - wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0) + nlmode = params->p2p ? + NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; + if (drv->nlmode != nlmode && + wpa_driver_nl80211_set_mode(priv, nlmode) < 0) return -1; retry: @@ -3159,8 +4514,7 @@ retry: wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)", drv->ifindex); - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_AUTHENTICATE, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE); for (i = 0; i < 4; i++) { if (!params->wep_key[i]) @@ -3218,8 +4572,9 @@ retry: ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " - "(%s)", ret, strerror(-ret)); + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: MLME command failed (auth): ret=%d (%s)", + ret, strerror(-ret)); count++; if (ret == -EALREADY && count == 1 && params->bssid && !params->local_state_change) { @@ -3236,6 +4591,49 @@ retry: nlmsg_free(msg); goto retry; } + + if (ret == -ENOENT && params->freq && !is_retry) { + /* + * cfg80211 has likely expired the BSS entry even + * though it was previously available in our internal + * BSS table. To recover quickly, start a single + * channel scan on the specified channel. + */ + struct wpa_driver_scan_params scan; + int freqs[2]; + + os_memset(&scan, 0, sizeof(scan)); + scan.num_ssids = 1; + if (params->ssid) { + scan.ssids[0].ssid = params->ssid; + scan.ssids[0].ssid_len = params->ssid_len; + } + freqs[0] = params->freq; + freqs[1] = 0; + scan.freqs = freqs; + wpa_printf(MSG_DEBUG, "nl80211: Trigger single " + "channel scan to refresh cfg80211 BSS " + "entry"); + ret = wpa_driver_nl80211_scan(bss, &scan); + if (ret == 0) { + nl80211_copy_auth_params(drv, params); + drv->scan_for_auth = 1; + } + } else if (is_retry) { + /* + * Need to indicate this with an event since the return + * value from the retry is not delivered to core code. + */ + union wpa_event_data event; + wpa_printf(MSG_DEBUG, "nl80211: Authentication retry " + "failed"); + os_memset(&event, 0, sizeof(event)); + os_memcpy(event.timeout_event.addr, drv->auth_bssid_, + ETH_ALEN); + wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT, + &event); + } + goto nla_put_failure; } ret = 0; @@ -3248,6 +4646,45 @@ nla_put_failure: } +static int wpa_driver_nl80211_authenticate_retry( + struct wpa_driver_nl80211_data *drv) +{ + struct wpa_driver_auth_params params; + struct i802_bss *bss = &drv->first_bss; + int i; + + wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again"); + + os_memset(¶ms, 0, sizeof(params)); + params.freq = drv->auth_freq; + params.auth_alg = drv->auth_alg; + params.wep_tx_keyidx = drv->auth_wep_tx_keyidx; + params.local_state_change = drv->auth_local_state_change; + params.p2p = drv->auth_p2p; + + if (!is_zero_ether_addr(drv->auth_bssid_)) + params.bssid = drv->auth_bssid_; + + if (drv->auth_ssid_len) { + params.ssid = drv->auth_ssid; + params.ssid_len = drv->auth_ssid_len; + } + + params.ie = drv->auth_ie; + params.ie_len = drv->auth_ie_len; + + for (i = 0; i < 4; i++) { + if (drv->auth_wep_key_len[i]) { + params.wep_key[i] = drv->auth_wep_key[i]; + params.wep_key_len[i] = drv->auth_wep_key_len[i]; + } + } + + drv->retry_auth = 1; + return wpa_driver_nl80211_authenticate(bss, ¶ms); +} + + struct phy_info_arg { u16 *num_modes; struct hostapd_hw_modes *modes; @@ -3300,6 +4737,7 @@ static int phy_info_handler(struct nl_msg *msg, void *arg) mode = &phy_info->modes[*(phy_info->num_modes)]; memset(mode, 0, sizeof(*mode)); + mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN; *(phy_info->num_modes) += 1; nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), @@ -3640,8 +5078,7 @@ static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_REG, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG); return send_and_recv_msgs(drv, msg, nl80211_get_reg, results); } @@ -3664,8 +5101,7 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) if (!msg) return NULL; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); @@ -3673,14 +5109,16 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) nl80211_set_ht40_flags(drv, &result); return wpa_driver_nl80211_add_11b(result.modes, num_modes); } + msg = NULL; nla_put_failure: + nlmsg_free(msg); return NULL; } -static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, - const void *data, size_t len, - int encrypt) +static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv, + const void *data, size_t len, + int encrypt, int noack) { __u8 rtap_hdr[] = { 0x00, 0x00, /* radiotap version */ @@ -3711,6 +5149,7 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, .msg_flags = 0, }; int res; + u16 txflags = 0; if (encrypt) rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; @@ -3721,6 +5160,10 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, return -1; } + if (noack) + txflags |= IEEE80211_RADIOTAP_F_TX_NOACK; + *(le16 *) &rtap_hdr[12] = host_to_le16(txflags); + res = sendmsg(drv->monitor_sock, &msg, 0); if (res < 0) { wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno)); @@ -3730,8 +5173,24 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, } +static int wpa_driver_nl80211_send_frame(struct i802_bss *bss, + const void *data, size_t len, + int encrypt, int noack) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + u64 cookie; + + if (drv->use_monitor) + return wpa_driver_nl80211_send_mntr(drv, data, len, + encrypt, noack); + + return nl80211_send_frame_cmd(bss, bss->freq, 0, data, len, + &cookie, 0, noack, 0); +} + + static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, - size_t data_len) + size_t data_len, int noack) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -3741,7 +5200,8 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, mgmt = (struct ieee80211_mgmt *) data; fc = le_to_host16(mgmt->frame_control); - if (drv->nlmode == NL80211_IFTYPE_STATION && + + if (is_sta_interface(drv->nlmode) && WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { /* @@ -3749,19 +5209,21 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, * but it works due to the single-threaded nature * of wpa_supplicant. */ - return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0, - data, data_len, NULL); + return nl80211_send_frame_cmd(bss, drv->last_mgmt_freq, 0, + data, data_len, NULL, 1, noack, + 1); } -#ifdef ANDROID_BRCM_P2P_PATCH - if (drv->nlmode == NL80211_IFTYPE_AP) { - wpa_printf(MSG_DEBUG, "%s: Sending frame on ap_oper_freq %d using nl80211_send_frame_cmd", __func__, drv->ap_oper_freq); - return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0, - data, data_len, &drv->send_action_cookie); +#ifdef ANDROID_P2P + if (is_ap_interface(drv->nlmode)) { + return nl80211_send_frame_cmd(bss, bss->freq, 0, + data, data_len, &drv->send_action_cookie, 0, noack, 1); } #else - if (drv->no_monitor_iface_capab && drv->nlmode == NL80211_IFTYPE_AP ) { - return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0, - data, data_len, NULL); + + if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) { + return nl80211_send_frame_cmd(bss, bss->freq, 0, + data, data_len, NULL, + 0, noack, 0); } #endif if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && @@ -3777,15 +5239,59 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3) encrypt = 0; } - wpa_printf(MSG_DEBUG, "%s: Sending frame using monitor interface/l2 socket", __func__); - return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt); + + return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, + noack); } -static int wpa_driver_nl80211_set_beacon(void *priv, - const u8 *head, size_t head_len, - const u8 *tail, size_t tail_len, - int dtim_period, int beacon_int) +static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble, + int slot, int ht_opmode, int ap_isolate, + int *basic_rates) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS); + + if (cts >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); + if (preamble >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); + if (slot >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); + if (ht_opmode >= 0) + NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode); + if (ap_isolate >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate); + + if (basic_rates) { + u8 rates[NL80211_MAX_SUPP_RATES]; + u8 rates_len = 0; + int i; + + for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; + i++) + rates[rates_len++] = basic_rates[i] / 5; + + NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); + } + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int wpa_driver_nl80211_set_ap(void *priv, + struct wpa_driver_ap_params *params) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -3794,6 +5300,10 @@ static int wpa_driver_nl80211_set_beacon(void *priv, int ret; int beacon_set; int ifindex = if_nametoindex(bss->ifname); + int num_suites; + u32 suites[10]; + u32 ver; + beacon_set = bss->beacon_set; msg = nlmsg_alloc(); @@ -3805,13 +5315,112 @@ static int wpa_driver_nl80211_set_beacon(void *priv, if (beacon_set) cmd = NL80211_CMD_SET_BEACON; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, cmd, 0); - NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head); - NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); + nl80211_cmd(drv, msg, 0, cmd); + NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head); + NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int); - NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period); + NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int); + NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + if (params->proberesp && params->proberesp_len) + NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len, + params->proberesp); + switch (params->hide_ssid) { + case NO_SSID_HIDING: + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_NOT_IN_USE); + break; + case HIDDEN_SSID_ZERO_LEN: + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_ZERO_LEN); + break; + case HIDDEN_SSID_ZERO_CONTENTS: + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_ZERO_CONTENTS); + break; + } + if (params->privacy) + NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); + if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) == + (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) { + /* Leave out the attribute */ + } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, + NL80211_AUTHTYPE_SHARED_KEY); + else + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, + NL80211_AUTHTYPE_OPEN_SYSTEM); + + ver = 0; + if (params->wpa_version & WPA_PROTO_WPA) + ver |= NL80211_WPA_VERSION_1; + if (params->wpa_version & WPA_PROTO_RSN) + ver |= NL80211_WPA_VERSION_2; + if (ver) + NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); + + num_suites = 0; + if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X) + suites[num_suites++] = WLAN_AKM_SUITE_8021X; + if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK) + suites[num_suites++] = WLAN_AKM_SUITE_PSK; + if (num_suites) { + NLA_PUT(msg, NL80211_ATTR_AKM_SUITES, + num_suites * sizeof(u32), suites); + } + + if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X && + params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) + NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT); + + num_suites = 0; + if (params->pairwise_ciphers & WPA_CIPHER_CCMP) + suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP; + if (params->pairwise_ciphers & WPA_CIPHER_TKIP) + suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP; + if (params->pairwise_ciphers & WPA_CIPHER_WEP104) + suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104; + if (params->pairwise_ciphers & WPA_CIPHER_WEP40) + suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40; + if (num_suites) { + NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, + num_suites * sizeof(u32), suites); + } + + switch (params->group_cipher) { + case WPA_CIPHER_CCMP: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_CCMP); + break; + case WPA_CIPHER_TKIP: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_TKIP); + break; + case WPA_CIPHER_WEP104: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_WEP104); + break; + case WPA_CIPHER_WEP40: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_WEP40); + break; + } + + if (params->beacon_ies) { + NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies), + wpabuf_head(params->beacon_ies)); + } + if (params->proberesp_ies) { + NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP, + wpabuf_len(params->proberesp_ies), + wpabuf_head(params->proberesp_ies)); + } + if (params->assocresp_ies) { + NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP, + wpabuf_len(params->assocresp_ies), + wpabuf_head(params->assocresp_ies)); + } ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret) { @@ -3819,29 +5428,36 @@ static int wpa_driver_nl80211_set_beacon(void *priv, ret, strerror(-ret)); } else { bss->beacon_set = 1; + nl80211_set_bss(bss, params->cts_protect, params->preamble, + params->short_slot_time, params->ht_opmode, + params->isolate, params->basic_rates); } -#if defined(ANDROID_BRCM_P2P_PATCH) && defined(HOSTAPD) +#if defined(ANDROID_P2P) && defined(HOSTAPD) wpa_driver_nl80211_probe_req_report(priv, 1); #endif return ret; nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } -static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv, +static int wpa_driver_nl80211_set_freq(struct i802_bss *bss, int freq, int ht_enabled, int sec_channel_offset) { + struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; int ret; + wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d " + "sec_channel_offset=%d)", + freq, ht_enabled, sec_channel_offset); msg = nlmsg_alloc(); if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); @@ -3856,7 +5472,7 @@ static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv, NL80211_CHAN_HT40PLUS); break; default: -#ifndef ANDROID_BRCM_P2P_PATCH +#ifndef ANDROID_P2P /* Should be change to HT20 as a default value because P2P firmware does not support 11n for BCM4329 */ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20); @@ -3869,50 +5485,102 @@ static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv, } ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret == 0) + msg = NULL; + if (ret == 0) { + bss->freq = freq; return 0; + } wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): " "%d (%s)", freq, ret, strerror(-ret)); nla_put_failure: + nlmsg_free(msg); return -1; } +static u32 sta_flags_nl80211(int flags) +{ + u32 f = 0; + + if (flags & WPA_STA_AUTHORIZED) + f |= BIT(NL80211_STA_FLAG_AUTHORIZED); + if (flags & WPA_STA_WMM) + f |= BIT(NL80211_STA_FLAG_WME); + if (flags & WPA_STA_SHORT_PREAMBLE) + f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); + if (flags & WPA_STA_MFP) + f |= BIT(NL80211_STA_FLAG_MFP); + if (flags & WPA_STA_TDLS_PEER) + f |= BIT(NL80211_STA_FLAG_TDLS_PEER); + + return f; +} + + static int wpa_driver_nl80211_sta_add(void *priv, struct hostapd_sta_add_params *params) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; + struct nl_msg *msg, *wme = NULL; + struct nl80211_sta_flag_update upd; int ret = -ENOBUFS; + if ((params->flags & WPA_STA_TDLS_PEER) && + !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) + return -EOPNOTSUPP; + msg = nlmsg_alloc(); if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_STATION, 0); + nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION : + NL80211_CMD_NEW_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr); - NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len, params->supp_rates); - NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, - params->listen_interval); + if (!params->set) { + NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); + NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, + params->listen_interval); + } if (params->ht_capabilities) { NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sizeof(*params->ht_capabilities), params->ht_capabilities); } + os_memset(&upd, 0, sizeof(upd)); + upd.mask = sta_flags_nl80211(params->flags); + upd.set = upd.mask; + NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); + + if (params->flags & WPA_STA_WMM) { + wme = nlmsg_alloc(); + if (!wme) + goto nla_put_failure; + + NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES, + params->qosinfo & WMM_QOSINFO_STA_AC_MASK); + NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP, + (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) & + WMM_QOSINFO_STA_SP_MASK); + nla_put_nested(msg, NL80211_ATTR_STA_WME, wme); + } + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (ret) - wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION " - "result: %d (%s)", ret, strerror(-ret)); + wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION " + "result: %d (%s)", params->set ? "SET" : "NEW", ret, + strerror(-ret)); if (ret == -EEXIST) ret = 0; nla_put_failure: + nlmsg_free(wme); + nlmsg_free(msg); return ret; } @@ -3928,8 +5596,7 @@ static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr) if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); @@ -3940,6 +5607,7 @@ static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr) return 0; return ret; nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -3951,26 +5619,46 @@ static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx); -#ifdef HOSTAPD /* stop listening for EAPOL on this interface */ del_ifidx(drv, ifidx); -#endif /* HOSTAPD */ msg = nlmsg_alloc(); if (!msg) goto nla_put_failure; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_INTERFACE, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return; + msg = NULL; nla_put_failure: + nlmsg_free(msg); wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx); } +static const char * nl80211_iftype_str(enum nl80211_iftype mode) +{ + switch (mode) { + case NL80211_IFTYPE_ADHOC: + return "ADHOC"; + case NL80211_IFTYPE_STATION: + return "STATION"; + case NL80211_IFTYPE_AP: + return "AP"; + case NL80211_IFTYPE_MONITOR: + return "MONITOR"; + case NL80211_IFTYPE_P2P_CLIENT: + return "P2P_CLIENT"; + case NL80211_IFTYPE_P2P_GO: + return "P2P_GO"; + default: + return "unknown"; + } +} + + static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, const char *ifname, enum nl80211_iftype iftype, @@ -3980,12 +5668,14 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, int ifidx; int ret = -ENOBUFS; + wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)", + iftype, nl80211_iftype_str(iftype)); + msg = nlmsg_alloc(); if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_INTERFACE, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); @@ -4010,8 +5700,10 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, } ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (ret) { nla_put_failure: + nlmsg_free(msg); wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)", ifname, ret, strerror(-ret)); return ret; @@ -4024,13 +5716,11 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, if (ifidx <= 0) return -1; -#ifdef HOSTAPD /* start listening for EAPOL on this interface */ add_ifidx(drv, ifidx); -#endif /* HOSTAPD */ if (addr && iftype != NL80211_IFTYPE_MONITOR && - linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) { + linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) { nl80211_remove_iface(drv, ifidx); return -1; } @@ -4047,7 +5737,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds); - /* if error occured and interface exists already */ + /* if error occurred and interface exists already */ if (ret == -ENFILE && if_nametoindex(ifname)) { wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname); @@ -4059,7 +5749,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, wds); } - if (ret >= 0 && drv->disable_11b_rates) + if (ret >= 0 && is_p2p_interface(iftype)) nl80211_disable_11b_rates(drv, ret, 1); return ret; @@ -4089,10 +5779,20 @@ static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok) static void from_unknown_sta(struct wpa_driver_nl80211_data *drv, u8 *buf, size_t len) { + struct ieee80211_hdr *hdr = (void *)buf; + u16 fc; union wpa_event_data event; + + if (len < sizeof(*hdr)) + return; + + fc = le_to_host16(hdr->frame_control); + os_memset(&event, 0, sizeof(event)); - event.rx_from_unknown.frame = buf; - event.rx_from_unknown.len = len; + event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len); + event.rx_from_unknown.addr = hdr->addr2; + event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) == + (WLAN_FC_FROMDS | WLAN_FC_TODS); wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); } @@ -4350,6 +6050,10 @@ static int add_monitor_filter(int s) static void nl80211_remove_monitor_interface( struct wpa_driver_nl80211_data *drv) { + drv->monitor_refcount--; + if (drv->monitor_refcount > 0) + return; + if (drv->monitor_ifidx >= 0) { nl80211_remove_iface(drv, drv->monitor_ifidx); drv->monitor_ifidx = -1; @@ -4369,11 +6073,25 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) struct sockaddr_ll ll; int optval; socklen_t optlen; -#ifdef ANDROID_BRCM_P2P_PATCH - snprintf(buf, IFNAMSIZ, "%s%s", WPA_MONITOR_IFNAME_PREFIX, drv->first_bss.ifname); -#else - snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname); -#endif + + if (drv->monitor_ifidx >= 0) { + drv->monitor_refcount++; + return 0; + } + + if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) { + /* + * P2P interface name is of the format p2p-%s-%d. For monitor + * interface name corresponding to P2P GO, replace "p2p-" with + * "mon-" to retain the same interface name length and to + * indicate that it is a monitor interface. + */ + snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4); + } else { + /* Non-P2P interface with AP functionality. */ + snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname); + } + buf[IFNAMSIZ - 1] = '\0'; drv->monitor_ifidx = @@ -4381,15 +6099,21 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) 0); if (drv->monitor_ifidx == -EOPNOTSUPP) { + /* + * This is backward compatibility for a few versions of + * the kernel only that didn't advertise the right + * attributes for the only driver that then supported + * AP mode w/o monitor -- ath6kl. + */ wpa_printf(MSG_DEBUG, "nl80211: Driver does not support " "monitor interface type - try to run without it"); - drv->no_monitor_iface_capab = 1; + drv->device_ap_sme = 1; } if (drv->monitor_ifidx < 0) return -1; - if (linux_set_iface_flags(drv->ioctl_sock, buf, 1)) + if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1)) goto error; memset(&ll, 0, sizeof(ll)); @@ -4433,6 +6157,98 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) } +static int nl80211_setup_ap(struct i802_bss *bss) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + + wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d " + "use_monitor=%d", drv->device_ap_sme, drv->use_monitor); + + /* + * Disable Probe Request reporting unless we need it in this way for + * devices that include the AP SME, in the other case (unless using + * monitor iface) we'll get it through the nl_mgmt socket instead. + */ + if (!drv->device_ap_sme) + wpa_driver_nl80211_probe_req_report(bss, 0); + + if (!drv->device_ap_sme && !drv->use_monitor) + if (nl80211_mgmt_subscribe_ap(bss)) + return -1; + + if (drv->device_ap_sme && !drv->use_monitor) + if (nl80211_mgmt_subscribe_ap_dev_sme(bss)) + return -1; + + if (!drv->device_ap_sme && drv->use_monitor && + nl80211_create_monitor_interface(drv) && + !drv->device_ap_sme) + return -1; + + if (drv->device_ap_sme && + wpa_driver_nl80211_probe_req_report(bss, 1) < 0) { + wpa_printf(MSG_DEBUG, "nl80211: Failed to enable " + "Probe Request frame reporting in AP mode"); + /* Try to survive without this */ + } + +#ifdef ANDROID_P2P + /* For AP mode, enable probe req report even if device_ap_sme + * is not enabled + */ + wpa_printf(MSG_DEBUG, "nl80211: Enabling probe req report"); + wpa_driver_nl80211_probe_req_report(bss, 1); +#endif + + return 0; +} + + +static void nl80211_teardown_ap(struct i802_bss *bss) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + + if (drv->device_ap_sme) { + wpa_driver_nl80211_probe_req_report(bss, 0); + if (!drv->use_monitor) + nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)"); + } else if (drv->use_monitor) + nl80211_remove_monitor_interface(drv); + else + nl80211_mgmt_unsubscribe(bss, "AP teardown"); + + bss->beacon_set = 0; +} + + +static int nl80211_send_eapol_data(struct i802_bss *bss, + const u8 *addr, const u8 *data, + size_t data_len) +{ + struct sockaddr_ll ll; + int ret; + + if (bss->drv->eapol_tx_sock < 0) { + wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL"); + return -1; + } + + os_memset(&ll, 0, sizeof(ll)); + ll.sll_family = AF_PACKET; + ll.sll_ifindex = bss->ifindex; + ll.sll_protocol = htons(ETH_P_PAE); + ll.sll_halen = ETH_ALEN; + os_memcpy(ll.sll_addr, addr, ETH_ALEN); + ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0, + (struct sockaddr *) &ll, sizeof(ll)); + if (ret < 0) + wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s", + strerror(errno)); + + return ret; +} + + static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; static int wpa_driver_nl80211_hapd_send_eapol( @@ -4447,6 +6263,9 @@ static int wpa_driver_nl80211_hapd_send_eapol( int res; int qos = flags & WPA_STA_WMM; + if (drv->device_ap_sme || !drv->use_monitor) + return nl80211_send_eapol_data(bss, addr, data, data_len); + len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + data_len; hdr = os_zalloc(len); @@ -4484,7 +6303,7 @@ static int wpa_driver_nl80211_hapd_send_eapol( pos += 2; memcpy(pos, data, data_len); - res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt); + res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0); if (res < 0) { wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " "failed: %d (%s)", @@ -4496,23 +6315,6 @@ static int wpa_driver_nl80211_hapd_send_eapol( } -static u32 sta_flags_nl80211(int flags) -{ - u32 f = 0; - - if (flags & WPA_STA_AUTHORIZED) - f |= BIT(NL80211_STA_FLAG_AUTHORIZED); - if (flags & WPA_STA_WMM) - f |= BIT(NL80211_STA_FLAG_WME); - if (flags & WPA_STA_SHORT_PREAMBLE) - f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); - if (flags & WPA_STA_MFP) - f |= BIT(NL80211_STA_FLAG_MFP); - - return f; -} - - static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or, int flags_and) @@ -4532,8 +6334,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, return -ENOMEM; } - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); @@ -4555,6 +6356,9 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, if (total_flags & WPA_STA_MFP) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP); + if (total_flags & WPA_STA_TDLS_PEER) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER); + if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) goto nla_put_failure; @@ -4567,6 +6371,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: + nlmsg_free(msg); nlmsg_free(flags); return -ENOBUFS; } @@ -4575,20 +6380,21 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params) { - if (params->p2p) + enum nl80211_iftype nlmode; + + if (params->p2p) { wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P " "group (GO)"); - if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) || - wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) { + nlmode = NL80211_IFTYPE_P2P_GO; + } else + nlmode = NL80211_IFTYPE_AP; + + if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) || + wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) { nl80211_remove_monitor_interface(drv); return -1; } - /* TODO: setup monitor interface (and add code somewhere to remove this - * when AP mode is stopped; associate with mode != 2 or drv_deinit) */ - wpa_printf(MSG_DEBUG, "nl80211: Update ap_oper_freq with params->freq %d", params->freq); - drv->ap_oper_freq = params->freq; - return 0; } @@ -4602,8 +6408,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv) if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_LEAVE_IBSS, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; @@ -4631,7 +6436,8 @@ static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex); - if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) { + if (wpa_driver_nl80211_set_mode(&drv->first_bss, + NL80211_IFTYPE_ADHOC)) { wpa_printf(MSG_INFO, "nl80211: Failed to set interface into " "IBSS mode"); return -1; @@ -4642,8 +6448,7 @@ retry: if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_JOIN_IBSS, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid)) @@ -4696,6 +6501,55 @@ nla_put_failure: } +static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv, + u8 *bssid) +{ + struct nl_msg *msg; + int ret; + struct nl80211_bss_info_arg arg; + + os_memset(&arg, 0, sizeof(arg)); + msg = nlmsg_alloc(); + if (!msg) + goto nla_put_failure; + + nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + arg.drv = drv; + ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); + msg = NULL; + if (ret == 0) { + if (is_zero_ether_addr(arg.assoc_bssid)) + return -ENOTCONN; + os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN); + return 0; + } + wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d " + "(%s)", ret, strerror(-ret)); +nla_put_failure: + nlmsg_free(msg); + return drv->assoc_freq; +} + + +static int nl80211_disconnect(struct wpa_driver_nl80211_data *drv, + const u8 *bssid) +{ + u8 addr[ETH_ALEN]; + + if (bssid == NULL) { + int res = nl80211_get_assoc_bssid(drv, addr); + if (res) + return res; + bssid = addr; + } + + return wpa_driver_nl80211_disconnect(drv, bssid, + WLAN_REASON_PREV_AUTH_NOT_VALID); +} + + static int wpa_driver_nl80211_connect( struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params) @@ -4710,8 +6564,7 @@ static int wpa_driver_nl80211_connect( return -1; wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex); - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_CONNECT, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->bssid) { @@ -4766,15 +6619,15 @@ static int wpa_driver_nl80211_connect( NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); skip_auth_type: - if (params->wpa_ie && params->wpa_ie_len) { - enum nl80211_wpa_versions ver; + if (params->wpa_proto) { + enum nl80211_wpa_versions ver = 0; - if (params->wpa_ie[0] == WLAN_EID_RSN) - ver = NL80211_WPA_VERSION_2; - else - ver = NL80211_WPA_VERSION_1; + if (params->wpa_proto & WPA_PROTO_WPA) + ver |= NL80211_WPA_VERSION_1; + if (params->wpa_proto & WPA_PROTO_RSN) + ver |= NL80211_WPA_VERSION_2; - wpa_printf(MSG_DEBUG, " * WPA Version %d", ver); + wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver); NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); } @@ -4845,6 +6698,14 @@ skip_auth_type: if (ret) { wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d " "(%s)", ret, strerror(-ret)); + /* + * cfg80211 does not currently accept new connection if we are + * already connected. As a workaround, force disconnection and + * try again once the driver indicates it completed + * disconnection. + */ + if (ret == -EALREADY) + nl80211_disconnect(drv, params->bssid); goto nla_put_failure; } ret = 0; @@ -4872,7 +6733,10 @@ static int wpa_driver_nl80211_associate( return wpa_driver_nl80211_ibss(drv, params); if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { - if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0) + enum nl80211_iftype nlmode = params->p2p ? + NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; + + if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0) return -1; return wpa_driver_nl80211_connect(drv, params); } @@ -4885,8 +6749,7 @@ static int wpa_driver_nl80211_associate( wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)", drv->ifindex); - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_ASSOCIATE, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->bssid) { @@ -4979,8 +6842,9 @@ static int wpa_driver_nl80211_associate( ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " - "(%s)", ret, strerror(-ret)); + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: MLME command failed (assoc): ret=%d (%s)", + ret, strerror(-ret)); nl80211_dump_scan(drv); goto nla_put_failure; } @@ -4995,58 +6859,53 @@ nla_put_failure: static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv, - int ifindex, int mode) + int ifindex, enum nl80211_iftype mode) { struct nl_msg *msg; int ret = -ENOBUFS; + wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)", + ifindex, mode, nl80211_iftype_str(mode)); + msg = nlmsg_alloc(); if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_INTERFACE, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (!ret) return 0; nla_put_failure: + nlmsg_free(msg); wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:" " %d (%s)", ifindex, mode, ret, strerror(-ret)); return ret; } -static int wpa_driver_nl80211_set_mode(void *priv, int mode) +static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, + enum nl80211_iftype nlmode) { - struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; int ret = -1; - int nlmode; int i; + int was_ap = is_ap_interface(drv->nlmode); + int res; - switch (mode) { - case 0: - nlmode = NL80211_IFTYPE_STATION; - break; - case 1: - nlmode = NL80211_IFTYPE_ADHOC; - break; - case 2: - nlmode = NL80211_IFTYPE_AP; - break; - default: - return -1; - } - - if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) { + res = nl80211_set_mode(drv, drv->ifindex, nlmode); + if (res == 0) { drv->nlmode = nlmode; ret = 0; goto done; } + if (res == -ENODEV) + return -1; + if (nlmode == drv->nlmode) { wpa_printf(MSG_DEBUG, "nl80211: Interface already in " "requested mode - ignore error"); @@ -5061,15 +6920,21 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode) wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting " "interface down"); for (i = 0; i < 10; i++) { - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) == - 0) { + res = linux_set_iface_flags(drv->global->ioctl_sock, + bss->ifname, 0); + if (res == -EACCES || res == -ENODEV) + break; + if (res == 0) { /* Try to set the mode again while the interface is * down */ ret = nl80211_set_mode(drv, drv->ifindex, nlmode); - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, - 1)) + if (ret == -EACCES) + break; + res = linux_set_iface_flags(drv->global->ioctl_sock, + bss->ifname, 1); + if (res && !ret) ret = -1; - if (!ret) + else if (ret != -EBUSY) break; } else wpa_printf(MSG_DEBUG, "nl80211: Failed to set " @@ -5081,26 +6946,34 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode) wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while " "interface is down"); drv->nlmode = nlmode; + drv->ignore_if_down_event = 1; } done: - if (!ret && nlmode == NL80211_IFTYPE_AP) { + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d " + "from %d failed", nlmode, drv->nlmode); + return ret; + } + + if (is_ap_interface(nlmode)) { + nl80211_mgmt_unsubscribe(bss, "start AP"); /* Setup additional AP mode functionality if needed */ - if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 && - nl80211_create_monitor_interface(drv) && - !drv->no_monitor_iface_capab) + if (nl80211_setup_ap(bss)) return -1; - } else if (!ret && nlmode != NL80211_IFTYPE_AP) { + } else if (was_ap) { /* Remove additional AP mode functionality */ - nl80211_remove_monitor_interface(drv); - bss->beacon_set = 0; + nl80211_teardown_ap(bss); + } else { + nl80211_mgmt_unsubscribe(bss, "mode change"); } - if (ret) - wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d " - "from %d failed", nlmode, drv->nlmode); + if (!is_ap_interface(nlmode) && + nl80211_mgmt_subscribe_non_ap(bss) < 0) + wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action " + "frame processing - ignore for now"); - return ret; + return 0; } @@ -5124,7 +6997,7 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state) wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", __func__, drv->operstate, state, state ? "UP" : "DORMANT"); drv->operstate = state; - return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, + return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, state ? IF_OPER_UP : IF_OPER_DORMANT); } @@ -5140,8 +7013,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); @@ -5155,6 +7027,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -5163,8 +7036,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) static int i802_set_freq(void *priv, struct hostapd_freq_params *freq) { struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled, + return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled, freq->sec_channel_offset); } @@ -5211,8 +7083,7 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_KEY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY); if (addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); @@ -5223,36 +7094,7 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, return send_and_recv_msgs(drv, msg, get_key_handler, seq); nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, - int mode) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - u8 rates[NL80211_MAX_SUPP_RATES]; - u8 rates_len = 0; - int i; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_BSS, 0); - - for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++) - rates[rates_len++] = basic_rates[i] / 5; - - NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -5274,15 +7116,16 @@ static int i802_set_rts(void *priv, int rts) else val = rts; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val); ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (!ret) return 0; nla_put_failure: + nlmsg_free(msg); wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: " "%d (%s)", rts, ret, strerror(-ret)); return ret; @@ -5306,15 +7149,16 @@ static int i802_set_frag(void *priv, int frag) else val = frag; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val); ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (!ret) return 0; nla_put_failure: + nlmsg_free(msg); wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold " "%d: %d (%s)", frag, ret, strerror(-ret)); return ret; @@ -5326,13 +7170,13 @@ static int i802_flush(void *priv) struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; + int res; msg = nlmsg_alloc(); if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); /* * XXX: FIX! this needs to flush all VLANs too @@ -5340,8 +7184,14 @@ static int i802_flush(void *priv) NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - return send_and_recv_msgs(drv, msg, NULL, NULL); + res = send_and_recv_msgs(drv, msg, NULL, NULL); + if (res) { + wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d " + "(%s)", res, strerror(-res)); + } + return res; nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -5409,14 +7259,14 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); return send_and_recv_msgs(drv, msg, get_sta_handler, data); nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -5433,8 +7283,7 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_WIPHY, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); @@ -5474,59 +7323,13 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs, if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return 0; + msg = NULL; nla_put_failure: + nlmsg_free(msg); return -1; } -static int i802_set_bss(void *priv, int cts, int preamble, int slot, - int ht_opmode) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_BSS, 0); - - if (cts >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); - if (preamble >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); - if (slot >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); - if (ht_opmode >= 0) - NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_cts_protect(void *priv, int value) -{ - return i802_set_bss(priv, value, -1, -1, -1); -} - - -static int i802_set_preamble(void *priv, int value) -{ - return i802_set_bss(priv, -1, value, -1, -1); -} - - -static int i802_set_short_slot_time(void *priv, int value) -{ - return i802_set_bss(priv, -1, -1, value, -1); -} - - static int i802_set_sta_vlan(void *priv, const u8 *addr, const char *ifname, int vlan_id) { @@ -5539,8 +7342,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_STATION, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); @@ -5549,6 +7351,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr, if_nametoindex(ifname)); ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr=" MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)", @@ -5556,23 +7359,11 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr, strerror(-ret)); } nla_put_failure: + nlmsg_free(msg); return ret; } -static int i802_set_ht_params(void *priv, const u8 *ht_capab, - size_t ht_capab_len, const u8 *ht_oper, - size_t ht_oper_len) -{ - if (ht_oper_len >= 6) { - /* ht opmode uses 16bit in octet 5 & 6 */ - u16 ht_opmode = le_to_host16(((u16 *) ht_oper)[2]); - return i802_set_bss(priv, -1, -1, -1, ht_opmode); - } else - return -1; -} - - static int i802_get_inact_sec(void *priv, const u8 *addr) { struct hostap_sta_driver_data data; @@ -5610,7 +7401,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, mgmt.u.deauth.reason_code = host_to_le16(reason); return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth)); + sizeof(mgmt.u.deauth), 0); } @@ -5629,7 +7420,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, mgmt.u.disassoc.reason_code = host_to_le16(reason); return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc)); + sizeof(mgmt.u.disassoc), 0); } #endif /* HOSTAPD || CONFIG_AP */ @@ -5716,11 +7507,11 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, NULL, 1) < 0) return -1; if (bridge_ifname && - linux_br_add_if(drv->ioctl_sock, bridge_ifname, - name) < 0) + linux_br_add_if(drv->global->ioctl_sock, + bridge_ifname, name) < 0) return -1; } - linux_set_iface_flags(drv->ioctl_sock, name, 1); + linux_set_iface_flags(drv->global->ioctl_sock, name, 1); return i802_set_sta_vlan(priv, addr, name, 0); } else { i802_set_sta_vlan(priv, addr, bss->ifname, 0); @@ -5764,7 +7555,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv, * Bridge was configured, but the bridge device does * not exist. Try to add it now. */ - if (linux_br_add(drv->ioctl_sock, brname) < 0) { + if (linux_br_add(drv->global->ioctl_sock, brname) < 0) { wpa_printf(MSG_ERROR, "nl80211: Failed to add the " "bridge interface %s: %s", brname, strerror(errno)); @@ -5780,7 +7571,8 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from " "bridge %s", ifname, in_br); - if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) { + if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) < + 0) { wpa_printf(MSG_ERROR, "nl80211: Failed to " "remove interface %s from bridge " "%s: %s", @@ -5791,7 +7583,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s", ifname, brname); - if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) { + if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) { wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s " "into bridge %s: %s", ifname, brname, strerror(errno)); @@ -5813,12 +7605,15 @@ static void *i802_init(struct hostapd_data *hapd, int ifindex, br_ifindex; int br_added = 0; - bss = wpa_driver_nl80211_init(hapd, params->ifname, NULL); + bss = wpa_driver_nl80211_init(hapd, params->ifname, + params->global_priv); if (bss == NULL) return NULL; drv = bss->drv; drv->nlmode = NL80211_IFTYPE_AP; + drv->eapol_sock = -1; + if (linux_br_get(brname, params->ifname) == 0) { wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s", params->ifname, brname); @@ -5846,16 +7641,16 @@ static void *i802_init(struct hostapd_data *hapd, /* start listening for EAPOL on the default AP interface */ add_ifidx(drv, drv->ifindex); - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0)) + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0)) goto failed; if (params->bssid) { - if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname, + if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, params->bssid)) goto failed; } - if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) { + if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) { wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s " "into AP mode", bss->ifname); goto failed; @@ -5865,7 +7660,7 @@ static void *i802_init(struct hostapd_data *hapd, i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0) goto failed; - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) goto failed; drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); @@ -5880,25 +7675,16 @@ static void *i802_init(struct hostapd_data *hapd, goto failed; } - if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr)) + if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + params->own_addr)) goto failed; + memcpy(bss->addr, params->own_addr, ETH_ALEN); + return bss; failed: - nl80211_remove_monitor_interface(drv); - rfkill_deinit(drv->rfkill); - netlink_deinit(drv->netlink); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - - genl_family_put(drv->nl80211); - nl_cache_free(drv->nl_cache); - nl80211_handle_destroy(drv->nl_handle); - nl_cb_put(drv->nl_cb); - eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); - - os_free(drv); + wpa_driver_nl80211_deinit(bss); return NULL; } @@ -5938,7 +7724,7 @@ static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr) struct wpa_driver_nl80211_data *drv; dl_list_for_each(drv, &global->interfaces, struct wpa_driver_nl80211_data, list) { - if (os_memcmp(addr, drv->addr, ETH_ALEN) == 0) + if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0) return 1; } return 0; @@ -5953,9 +7739,9 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv, if (!drv->global) return -1; - os_memcpy(new_addr, drv->addr, ETH_ALEN); + os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN); for (idx = 0; idx < 64; idx++) { - new_addr[0] = drv->addr[0] | 0x02; + new_addr[0] = drv->first_bss.addr[0] | 0x02; new_addr[0] ^= idx << 2; if (!nl80211_addr_in_use(drv->global, new_addr)) break; @@ -6004,7 +7790,8 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, } if (!addr && - linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0) { + linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + if_addr) < 0) { nl80211_remove_iface(drv, ifidx); return -1; } @@ -6016,10 +7803,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, /* Enforce unique P2P Interface Address */ u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN]; - if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) - < 0 || - linux_get_ifhwaddr(drv->ioctl_sock, ifname, new_addr) < 0) - { + if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + own_addr) < 0 || + linux_get_ifhwaddr(drv->global->ioctl_sock, ifname, + new_addr) < 0) { nl80211_remove_iface(drv, ifidx); return -1; } @@ -6030,7 +7817,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, nl80211_remove_iface(drv, ifidx); return -1; } - if (linux_set_ifhwaddr(drv->ioctl_sock, ifname, + if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, new_addr) < 0) { nl80211_remove_iface(drv, ifidx); return -1; @@ -6051,21 +7838,27 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, } if (type == WPA_IF_AP_BSS) { - if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) { + if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1)) + { nl80211_remove_iface(drv, ifidx); os_free(new_bss); return -1; } os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ); + os_memcpy(new_bss->addr, if_addr, ETH_ALEN); new_bss->ifindex = ifidx; new_bss->drv = drv; new_bss->next = drv->first_bss.next; drv->first_bss.next = new_bss; if (drv_priv) *drv_priv = new_bss; + nl80211_init_bss(new_bss); } #endif /* HOSTAPD */ + if (drv->global) + drv->global->if_add_ifindex = ifidx; + return 0; } @@ -6085,14 +7878,14 @@ static int wpa_driver_nl80211_if_remove(void *priv, #ifdef HOSTAPD if (bss->added_if_into_bridge) { - if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname) - < 0) + if (linux_br_del_if(drv->global->ioctl_sock, bss->brname, + bss->ifname) < 0) wpa_printf(MSG_INFO, "nl80211: Failed to remove " "interface %s from bridge %s: %s", bss->ifname, bss->brname, strerror(errno)); } if (bss->added_bridge) { - if (linux_br_del(drv->ioctl_sock, bss->brname) < 0) + if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0) wpa_printf(MSG_INFO, "nl80211: Failed to remove " "bridge %s: %s", bss->brname, strerror(errno)); @@ -6111,6 +7904,7 @@ static int wpa_driver_nl80211_if_remove(void *priv, for (tbss = &drv->first_bss; tbss; tbss = tbss->next) { if (tbss->next == bss) { tbss->next = bss->next; + nl80211_destroy_bss(bss); os_free(bss); bss = NULL; break; @@ -6139,11 +7933,13 @@ static int cookie_handler(struct nl_msg *msg, void *arg) } -static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv, +static int nl80211_send_frame_cmd(struct i802_bss *bss, unsigned int freq, unsigned int wait, const u8 *buf, size_t buf_len, - u64 *cookie_out) + u64 *cookie_out, int no_cck, int no_ack, + int offchanok) { + struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; u64 cookie; int ret = -1; @@ -6152,16 +7948,21 @@ static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_FRAME, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); -#ifndef ANDROID_BRCM_P2P_PATCH +#ifndef ANDROID_P2P if (wait) NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait); #endif - NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); + if (offchanok) + NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); + if (no_cck) + NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE); + if (no_ack) + NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK); + NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf); cookie = 0; @@ -6173,11 +7974,12 @@ static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv, freq, wait); goto nla_put_failure; } - wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted; " - "cookie 0x%llx", (long long unsigned int) cookie); + wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; " + "cookie 0x%llx", no_ack ? " (no ACK)" : "", + (long long unsigned int) cookie); if (cookie_out) - *cookie_out = cookie; + *cookie_out = no_ack ? (u64) -1 : cookie; nla_put_failure: nlmsg_free(msg); @@ -6189,7 +7991,8 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq, unsigned int wait_time, const u8 *dst, const u8 *src, const u8 *bssid, - const u8 *data, size_t data_len) + const u8 *data, size_t data_len, + int no_cck) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -6198,7 +8001,7 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq, struct ieee80211_hdr *hdr; wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, " - "wait=%d ms)", drv->ifindex, wait_time); + "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck); buf = os_zalloc(24 + data_len); if (buf == NULL) @@ -6211,12 +8014,14 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq, os_memcpy(hdr->addr2, src, ETH_ALEN); os_memcpy(hdr->addr3, bssid, ETH_ALEN); - if (drv->nlmode == NL80211_IFTYPE_AP) - ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len); + if (is_ap_interface(drv->nlmode)) + ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len, + 0); else - ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf, + ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf, 24 + data_len, - &drv->send_action_cookie); + &drv->send_action_cookie, + no_cck, 0, 1); os_free(buf); return ret; @@ -6234,8 +8039,7 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv) if (!msg) return; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_FRAME_WAIT_CANCEL, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie); @@ -6264,8 +8068,7 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_REMAIN_ON_CHANNEL, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); @@ -6273,17 +8076,20 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq, cookie = 0; ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); + msg = NULL; if (ret == 0) { wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie " "0x%llx for freq=%u MHz duration=%u", (long long unsigned int) cookie, freq, duration); drv->remain_on_chan_cookie = cookie; + drv->pending_remain_on_chan = 1; return 0; } wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel " "(freq=%d duration=%u): %d (%s)", freq, duration, ret, strerror(-ret)); nla_put_failure: + nlmsg_free(msg); return -1; } @@ -6309,18 +8115,19 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv) if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie); ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (ret == 0) return 0; wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: " "%d (%s)", ret, strerror(-ret)); nla_put_failure: + nlmsg_free(msg); return -1; } @@ -6331,60 +8138,43 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report) struct wpa_driver_nl80211_data *drv = bss->drv; if (!report) { - if (drv->nl_handle_preq) { + if (bss->nl_preq && drv->device_ap_sme && + is_ap_interface(drv->nlmode)) { + /* + * Do not disable Probe Request reporting that was + * enabled in nl80211_setup_ap(). + */ + wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of " + "Probe Request reporting nl_preq=%p while " + "in AP mode", bss->nl_preq); + } else if (bss->nl_preq) { + wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request " + "reporting nl_preq=%p", bss->nl_preq); eloop_unregister_read_sock( - nl_socket_get_fd(drv->nl_handle_preq)); - nl_cache_free(drv->nl_cache_preq); - nl80211_handle_destroy(drv->nl_handle_preq); - drv->nl_handle_preq = NULL; + nl_socket_get_fd(bss->nl_preq)); + nl_destroy_handles(&bss->nl_preq); } return 0; } - if (drv->nl_handle_preq) { + if (bss->nl_preq) { wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting " - "already on!"); + "already on! nl_preq=%p", bss->nl_preq); return 0; } - drv->nl_handle_preq = nl80211_handle_alloc(drv->nl_cb); - if (drv->nl_handle_preq == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate " - "netlink callbacks (preq)"); - goto out_err1; - } - - if (genl_connect(drv->nl_handle_preq)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to connect to " - "generic netlink (preq)"); - goto out_err2; + bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq"); + if (bss->nl_preq == NULL) return -1; - } + wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request " + "reporting nl_preq=%p", bss->nl_preq); -#ifdef CONFIG_LIBNL20 - if (genl_ctrl_alloc_cache(drv->nl_handle_preq, - &drv->nl_cache_preq) < 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache (preq)"); - goto out_err2; - } -#else /* CONFIG_LIBNL20 */ - drv->nl_cache_preq = genl_ctrl_alloc_cache(drv->nl_handle_preq); - if (drv->nl_cache_preq == NULL) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache (preq)"); - goto out_err2; - } -#endif /* CONFIG_LIBNL20 */ - - if (nl80211_register_frame(drv, drv->nl_handle_preq, + if (nl80211_register_frame(bss, bss->nl_preq, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_PROBE_REQ << 4), - NULL, 0) < 0) { - goto out_err3; - } - -#ifdef ANDROID_BRCM_P2P_PATCH + NULL, 0) < 0) + goto out_err; +#ifdef ANDROID_P2P if (drv->nlmode != NL80211_IFTYPE_AP && drv->nlmode != NL80211_IFTYPE_P2P_GO) { wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only " @@ -6392,49 +8182,51 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report) drv->nlmode); goto done; } - - if (nl80211_register_frame(drv, drv->nl_handle_preq, + if (nl80211_register_frame(bss, bss->nl_preq, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ASSOC_REQ << 4), NULL, 0) < 0) { - goto out_err3; + goto out_err; } - if (nl80211_register_frame(drv, drv->nl_handle_preq, + if (nl80211_register_frame(bss, bss->nl_preq, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_REASSOC_REQ << 4), NULL, 0) < 0) { - goto out_err3; + goto out_err; } - if (nl80211_register_frame(drv, drv->nl_handle_preq, + if (nl80211_register_frame(bss, bss->nl_preq, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_DISASSOC << 4), NULL, 0) < 0) { - goto out_err3; + goto out_err; } - - if (nl80211_register_frame(drv, drv->nl_handle_preq, + + if (nl80211_register_frame(bss, bss->nl_preq, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_DEAUTH << 4), NULL, 0) < 0) { - goto out_err3; + goto out_err; + } + + if (nl80211_register_frame(bss, bss->nl_preq, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_ACTION << 4), + NULL, 0) < 0) { + goto out_err; } done: -#endif - eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_preq), - wpa_driver_nl80211_event_receive, drv, - drv->nl_handle_preq); +#endif /* ANDROID_P2P */ + eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq), + wpa_driver_nl80211_event_receive, bss->nl_cb, + bss->nl_preq); return 0; - out_err3: - nl_cache_free(drv->nl_cache_preq); - out_err2: - nl80211_handle_destroy(drv->nl_handle_preq); - drv->nl_handle_preq = NULL; - out_err1: + out_err: + nl_destroy_handles(&bss->nl_preq); return -1; } @@ -6450,8 +8242,7 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_TX_BITRATE_MASK, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES); @@ -6466,8 +8257,10 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, band = nla_nest_start(msg, NL80211_BAND_2GHZ); if (!band) goto nla_put_failure; - NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8, - "\x0c\x12\x18\x24\x30\x48\x60\x6c"); + if (disabled) { + NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8, + "\x0c\x12\x18\x24\x30\x48\x60\x6c"); + } nla_nest_end(msg, band); nla_nest_end(msg, bands); @@ -6487,23 +8280,14 @@ nla_put_failure: } -static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - drv->disable_11b_rates = disabled; - return nl80211_disable_11b_rates(drv, drv->ifindex, disabled); -} - - static int wpa_driver_nl80211_deinit_ap(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - if (drv->nlmode != NL80211_IFTYPE_AP) + if (!is_ap_interface(drv->nlmode)) return -1; wpa_driver_nl80211_del_beacon(drv); - return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA); + return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION); } @@ -6511,7 +8295,7 @@ static void wpa_driver_nl80211_resume(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) { + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on " "resume event"); } @@ -6526,10 +8310,7 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap, int ret; u8 *data, *pos; size_t data_len; - u8 own_addr[ETH_ALEN]; - - if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0) - return -1; + const u8 *own_addr = bss->addr; if (action != 1) { wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action " @@ -6561,7 +8342,7 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap, ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0, drv->bssid, own_addr, drv->bssid, - data, data_len); + data, data_len, 0); os_free(data); return ret; @@ -6581,8 +8362,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis) if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_CQM, 0); + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); @@ -6599,8 +8379,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis) msg = NULL; nla_put_failure: - if (cqm) - nlmsg_free(cqm); + nlmsg_free(cqm); nlmsg_free(msg); return -1; } @@ -6621,34 +8400,58 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si) } -static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len, - int encrypt) +static int wpa_driver_nl80211_shared_freq(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt); -} + struct wpa_driver_nl80211_data *driver; + int freq = 0; + /* + * If the same PHY is in connected state with some other interface, + * then retrieve the assoc freq. + */ + wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s", + drv->phyname); -static int nl80211_set_intra_bss(void *priv, int enabled) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; + dl_list_for_each(driver, &drv->global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (drv == driver || + os_strcmp(drv->phyname, driver->phyname) != 0 || +#ifdef ANDROID_P2P + (!driver->associated && !is_ap_interface(driver->nlmode))) +#else + !driver->associated) +#endif + continue; - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; + wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s " + MACSTR, + driver->phyname, driver->first_bss.ifname, + MAC2STR(driver->first_bss.addr)); +#ifdef ANDROID_P2P + if(is_ap_interface(driver->nlmode)) + freq = driver->first_bss.freq; + else +#endif + freq = nl80211_get_assoc_freq(driver); + wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d", + drv->phyname, freq); + } - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_BSS, 0); + if (!freq) + wpa_printf(MSG_DEBUG, "nl80211: No shared interface for " + "PHY (%s) in associated state", drv->phyname); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, !enabled); + return freq; +} - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; + +static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len, + int encrypt) +{ + struct i802_bss *bss = priv; + return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0); } @@ -6668,6 +8471,15 @@ static int nl80211_set_param(void *priv, const char *param) drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; } +#ifdef ANDROID_P2P + if(os_strstr(param, "use_multi_chan_concurrent=1")) { + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel " + "concurrency"); + drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT; + } +#endif #endif /* CONFIG_P2P */ return 0; @@ -6677,11 +8489,42 @@ static int nl80211_set_param(void *priv, const char *param) static void * nl80211_global_init(void) { struct nl80211_global *global; + struct netlink_config *cfg; + global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; + global->ioctl_sock = -1; dl_list_init(&global->interfaces); + global->if_add_ifindex = -1; + + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) + goto err; + + cfg->ctx = global; + cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink; + cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink; + global->netlink = netlink_init(cfg); + if (global->netlink == NULL) { + os_free(cfg); + goto err; + } + + if (wpa_driver_nl80211_init_nl_global(global) < 0) + goto err; + + global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (global->ioctl_sock < 0) { + perror("socket(PF_INET,SOCK_DGRAM)"); + goto err; + } + return global; + +err: + nl80211_global_deinit(global); + return NULL; } @@ -6695,6 +8538,23 @@ static void nl80211_global_deinit(void *priv) "nl80211_global_deinit", dl_list_len(&global->interfaces)); } + + if (global->netlink) + netlink_deinit(global->netlink); + + nl_destroy_handles(&global->nl); + + if (global->nl_event) { + eloop_unregister_read_sock( + nl_socket_get_fd(global->nl_event)); + nl_destroy_handles(&global->nl_event); + } + + nl_cb_put(global->nl_cb); + + if (global->ioctl_sock >= 0) + close(global->ioctl_sock); + os_free(global); } @@ -6716,8 +8576,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid, if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, genl_family_get_id(bss->drv->nl80211), 0, 0, - cmd, 0); + nl80211_cmd(bss->drv, msg, 0, cmd); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); if (pmkid) @@ -6727,6 +8586,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid, return send_and_recv_msgs(bss->drv, msg, NULL, NULL); nla_put_failure: + nlmsg_free(msg); return -ENOBUFS; } @@ -6756,6 +8616,366 @@ static int nl80211_flush_pmkid(void *priv) } +static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck, + const u8 *replay_ctr) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nlattr *replay_nested; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA); + if (!replay_nested) + goto nla_put_failure; + + NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek); + NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck); + NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN, + replay_ctr); + + nla_nest_end(msg, replay_nested); + + send_and_recv_msgs(drv, msg, NULL, NULL); + return; + nla_put_failure: + nlmsg_free(msg); +} + + +static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr, + const u8 *addr, int qos) +{ + /* send data frame to poll STA and check whether + * this frame is ACKed */ + struct { + struct ieee80211_hdr hdr; + u16 qos_ctl; + } STRUCT_PACKED nulldata; + size_t size; + + /* Send data frame to poll STA and check whether this frame is ACKed */ + + os_memset(&nulldata, 0, sizeof(nulldata)); + + if (qos) { + nulldata.hdr.frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, + WLAN_FC_STYPE_QOS_NULL); + size = sizeof(nulldata); + } else { + nulldata.hdr.frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, + WLAN_FC_STYPE_NULLFUNC); + size = sizeof(struct ieee80211_hdr); + } + + nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS); + os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN); + os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); + os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); + + if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0) + wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to " + "send poll frame"); +} + +static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr, + int qos) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + if (!drv->poll_command_supported) { + nl80211_send_null_frame(bss, own_addr, addr, qos); + return; + } + + msg = nlmsg_alloc(); + if (!msg) + return; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + send_and_recv_msgs(drv, msg, NULL, NULL); + return; + nla_put_failure: + nlmsg_free(msg); +} + + +static int nl80211_set_power_save(struct i802_bss *bss, int enabled) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, + enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED); + return send_and_recv_msgs(bss->drv, msg, NULL, NULL); +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps, + int ctwindow) +{ + struct i802_bss *bss = priv; + + wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d " + "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow); + + if (opp_ps != -1 || ctwindow != -1) + return -1; /* Not yet supported */ + + if (legacy_ps == -1) + return 0; + if (legacy_ps != 0 && legacy_ps != 1) + return -1; /* Not yet supported */ + + return nl80211_set_power_save(bss, legacy_ps); +} + + +#ifdef CONFIG_TDLS + +static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, + u8 dialog_token, u16 status_code, + const u8 *buf, size_t len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) + return -EOPNOTSUPP; + + if (!dst) + return -EINVAL; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); + NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code); + NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token); + NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code); + NLA_PUT(msg, NL80211_ATTR_IE, len, buf); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + enum nl80211_tdls_operation nl80211_oper; + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) + return -EOPNOTSUPP; + + switch (oper) { + case TDLS_DISCOVERY_REQ: + nl80211_oper = NL80211_TDLS_DISCOVERY_REQ; + break; + case TDLS_SETUP: + nl80211_oper = NL80211_TDLS_SETUP; + break; + case TDLS_TEARDOWN: + nl80211_oper = NL80211_TDLS_TEARDOWN; + break; + case TDLS_ENABLE_LINK: + nl80211_oper = NL80211_TDLS_ENABLE_LINK; + break; + case TDLS_DISABLE_LINK: + nl80211_oper = NL80211_TDLS_DISABLE_LINK; + break; + case TDLS_ENABLE: + return 0; + case TDLS_DISABLE: + return 0; + default: + return -EINVAL; + } + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER); + NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + +#endif /* CONFIG TDLS */ + + +#ifdef ANDROID + +typedef struct android_wifi_priv_cmd { + char *buf; + int used_len; + int total_len; +} android_wifi_priv_cmd; + +static int drv_errors = 0; + +static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) +{ + drv_errors++; + if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv_errors = 0; + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); + } +} + + +static int android_priv_cmd(struct i802_bss *bss, const char *cmd) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct ifreq ifr; + android_wifi_priv_cmd priv_cmd; + char buf[MAX_DRV_CMD_SIZE]; + int ret; + + os_memset(&ifr, 0, sizeof(ifr)); + os_memset(&priv_cmd, 0, sizeof(priv_cmd)); + os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); + + os_memset(buf, 0, sizeof(buf)); + os_strlcpy(buf, cmd, sizeof(buf)); + + priv_cmd.buf = buf; + priv_cmd.used_len = sizeof(buf); + priv_cmd.total_len = sizeof(buf); + ifr.ifr_data = &priv_cmd; + + ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); + if (ret < 0) { + wpa_printf(MSG_ERROR, "%s: failed to issue private commands", + __func__); + wpa_driver_send_hang_msg(drv); + return ret; + } + + drv_errors = 0; + return 0; +} + + +static int android_pno_start(struct i802_bss *bss, + struct wpa_driver_scan_params *params) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct ifreq ifr; + android_wifi_priv_cmd priv_cmd; + int ret = 0, i = 0, bp; + char buf[WEXT_PNO_MAX_COMMAND_SIZE]; + + bp = WEXT_PNOSETUP_HEADER_SIZE; + os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); + buf[bp++] = WEXT_PNO_TLV_PREFIX; + buf[bp++] = WEXT_PNO_TLV_VERSION; + buf[bp++] = WEXT_PNO_TLV_SUBVERSION; + buf[bp++] = WEXT_PNO_TLV_RESERVED; + + while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) { + /* Check that there is enough space needed for 1 more SSID, the + * other sections and null termination */ + if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN + + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf)) + break; + wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan", + params->ssids[i].ssid, + params->ssids[i].ssid_len); + buf[bp++] = WEXT_PNO_SSID_SECTION; + buf[bp++] = params->ssids[i].ssid_len; + os_memcpy(&buf[bp], params->ssids[i].ssid, + params->ssids[i].ssid_len); + bp += params->ssids[i].ssid_len; + i++; + } + + buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", + WEXT_PNO_SCAN_INTERVAL); + bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; + + buf[bp++] = WEXT_PNO_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", + WEXT_PNO_REPEAT); + bp += WEXT_PNO_REPEAT_LENGTH; + + buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", + WEXT_PNO_MAX_REPEAT); + bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; + + memset(&ifr, 0, sizeof(ifr)); + memset(&priv_cmd, 0, sizeof(priv_cmd)); + os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); + + priv_cmd.buf = buf; + priv_cmd.used_len = bp; + priv_cmd.total_len = bp; + ifr.ifr_data = &priv_cmd; + + ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", + ret); + wpa_driver_send_hang_msg(drv); + return ret; + } + + drv_errors = 0; + + return android_priv_cmd(bss, "PNOFORCE 1"); +} + + +static int android_pno_stop(struct i802_bss *bss) +{ + return android_priv_cmd(bss, "PNOFORCE 0"); +} + +#endif /* ANDROID */ + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -6763,6 +8983,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .get_ssid = wpa_driver_nl80211_get_ssid, .set_key = wpa_driver_nl80211_set_key, .scan2 = wpa_driver_nl80211_scan, + .sched_scan = wpa_driver_nl80211_sched_scan, + .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan, .get_scan_results2 = wpa_driver_nl80211_get_scan_results, .deauthenticate = wpa_driver_nl80211_deauthenticate, .disassociate = wpa_driver_nl80211_disassociate, @@ -6776,7 +8998,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .set_operstate = wpa_driver_nl80211_set_operstate, .set_supp_port = wpa_driver_nl80211_set_supp_port, .set_country = wpa_driver_nl80211_set_country, - .set_beacon = wpa_driver_nl80211_set_beacon, + .set_ap = wpa_driver_nl80211_set_ap, .if_add = wpa_driver_nl80211_if_add, .if_remove = wpa_driver_nl80211_if_remove, .send_mlme = wpa_driver_nl80211_send_mlme, @@ -6798,13 +9020,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .sta_clear_stats = i802_sta_clear_stats, .set_rts = i802_set_rts, .set_frag = i802_set_frag, - .set_cts_protect = i802_set_cts_protect, - .set_preamble = i802_set_preamble, - .set_short_slot_time = i802_set_short_slot_time, .set_tx_queue_params = i802_set_tx_queue_params, .set_sta_vlan = i802_set_sta_vlan, - .set_ht_params = i802_set_ht_params, - .set_rate_sets = i802_set_rate_sets, .sta_deauth = i802_sta_deauth, .sta_disassoc = i802_sta_disassoc, #endif /* HOSTAPD || CONFIG_AP */ @@ -6815,22 +9032,30 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .cancel_remain_on_channel = wpa_driver_nl80211_cancel_remain_on_channel, .probe_req_report = wpa_driver_nl80211_probe_req_report, - .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates, .deinit_ap = wpa_driver_nl80211_deinit_ap, .resume = wpa_driver_nl80211_resume, .send_ft_action = nl80211_send_ft_action, .signal_monitor = nl80211_signal_monitor, .signal_poll = nl80211_signal_poll, .send_frame = nl80211_send_frame, - .set_intra_bss = nl80211_set_intra_bss, + .shared_freq = wpa_driver_nl80211_shared_freq, .set_param = nl80211_set_param, .get_radio_name = nl80211_get_radio_name, .add_pmkid = nl80211_add_pmkid, .remove_pmkid = nl80211_remove_pmkid, .flush_pmkid = nl80211_flush_pmkid, -#ifdef ANDROID_BRCM_P2P_PATCH - .get_noa = wpa_driver_get_p2p_noa, + .set_rekey_info = nl80211_set_rekey_info, + .poll_client = nl80211_poll_client, +#ifndef ANDROID_P2P + .set_p2p_powersave = nl80211_set_p2p_powersave, +#endif +#ifdef CONFIG_TDLS + .send_tdls_mgmt = nl80211_send_tdls_mgmt, + .tdls_oper = nl80211_tdls_oper, +#endif /* CONFIG_TDLS */ +#ifdef ANDROID_P2P .set_noa = wpa_driver_set_p2p_noa, + .get_noa = wpa_driver_get_p2p_noa, .set_p2p_powersave = wpa_driver_set_p2p_ps, .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie, #endif diff --git a/src/drivers/driver_osx.m b/src/drivers/driver_osx.m deleted file mode 100644 index 69ca4b5..0000000 --- a/src/drivers/driver_osx.m +++ /dev/null @@ -1,459 +0,0 @@ -/* - * WPA Supplicant - Mac OS X Apple80211 driver interface - * Copyright (c) 2007, Jouni Malinen <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "includes.h" -#define Boolean __DummyBoolean -#include <CoreFoundation/CoreFoundation.h> -#undef Boolean - -#include "common.h" -#include "driver.h" -#include "eloop.h" -#include "common/ieee802_11_defs.h" - -#include "Apple80211.h" - -struct wpa_driver_osx_data { - void *ctx; - WirelessRef wireless_ctx; - CFArrayRef scan_results; -}; - - -#ifndef CONFIG_NO_STDOUT_DEBUG -extern int wpa_debug_level; - -static void dump_dict_cb(const void *key, const void *value, void *context) -{ - if (MSG_DEBUG < wpa_debug_level) - return; - - wpa_printf(MSG_DEBUG, "Key:"); - CFShow(key); - wpa_printf(MSG_DEBUG, "Value:"); - CFShow(value); -} -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title) -{ -#ifndef CONFIG_NO_STDOUT_DEBUG - wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries", - title, (unsigned int) CFDictionaryGetCount(dict)); - CFDictionaryApplyFunction(dict, dump_dict_cb, NULL); -#endif /* CONFIG_NO_STDOUT_DEBUG */ -} - - -static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid) -{ - struct wpa_driver_osx_data *drv = priv; - WirelessError err; - WirelessInfo info; - int len; - - err = WirelessGetInfo(drv->wireless_ctx, &info); - if (err) { - wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d", - (int) err); - return -1; - } - if (!info.power) { - wpa_printf(MSG_DEBUG, "OSX: Wireless device power off"); - return -1; - } - - for (len = 0; len < 32; len++) - if (info.ssid[len] == 0) - break; - - os_memcpy(ssid, info.ssid, len); - return len; -} - - -static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid) -{ - struct wpa_driver_osx_data *drv = priv; - WirelessError err; - WirelessInfo info; - - err = WirelessGetInfo(drv->wireless_ctx, &info); - if (err) { - wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d", - (int) err); - return -1; - } - if (!info.power) { - wpa_printf(MSG_DEBUG, "OSX: Wireless device power off"); - return -1; - } - - os_memcpy(bssid, info.bssID, ETH_ALEN); - return 0; -} - - -static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx) -{ - wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -} - - -static int wpa_driver_osx_scan(void *priv, struct wpa_driver_scan_params *params) -{ - struct wpa_driver_osx_data *drv = priv; - WirelessError err; - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - - if (drv->scan_results) { - CFRelease(drv->scan_results); - drv->scan_results = NULL; - } - - if (ssid) { - CFStringRef data; - data = CFStringCreateWithBytes(kCFAllocatorDefault, - ssid, ssid_len, - kCFStringEncodingISOLatin1, - FALSE); - if (data == NULL) { - wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes " - "failed"); - return -1; - } - - err = WirelessDirectedScan(drv->wireless_ctx, - &drv->scan_results, 0, data); - CFRelease(data); - if (err) { - wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan " - "failed: 0x%08x", (unsigned int) err); - return -1; - } - } else { - err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0); - if (err) { - wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: " - "0x%08x", (unsigned int) err); - return -1; - } - } - - eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv, - drv->ctx); - return 0; -} - - -static void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res, - WirelessNetworkInfo *info) -{ - struct wpa_scan_res *result, **tmp; - size_t extra_len; - u8 *pos; - - extra_len = 2 + info->ssid_len; - - result = os_zalloc(sizeof(*result) + extra_len); - if (result == NULL) - return; - os_memcpy(result->bssid, info->bssid, ETH_ALEN); - result->freq = 2407 + info->channel * 5; - //result->beacon_int =; - result->caps = info->capability; - //result->qual = info->signal; - result->noise = info->noise; - - pos = (u8 *)(result + 1); - - *pos++ = WLAN_EID_SSID; - *pos++ = info->ssid_len; - os_memcpy(pos, info->ssid, info->ssid_len); - pos += info->ssid_len; - - result->ie_len = pos - (u8 *)(result + 1); - - tmp = os_realloc(res->res, - (res->num + 1) * sizeof(struct wpa_scan_res *)); - if (tmp == NULL) { - os_free(result); - return; - } - tmp[res->num++] = result; - res->res = tmp; -} - - -static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv) -{ - struct wpa_driver_osx_data *drv = priv; - struct wpa_scan_results *res; - size_t i, num; - - if (drv->scan_results == NULL) - return 0; - - num = CFArrayGetCount(drv->scan_results); - - res = os_zalloc(sizeof(*res)); - if (res == NULL) - return NULL; - - for (i = 0; i < num; i++) - wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *) - CFDataGetBytePtr(CFArrayGetValueAtIndex( - drv->scan_results, i))); - - return res; -} - - -static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_driver_osx_data *drv = eloop_ctx; - u8 bssid[ETH_ALEN]; - CFDictionaryRef ai; - - if (wpa_driver_osx_get_bssid(drv, bssid) != 0) { - eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout, - drv, drv->ctx); - return; - } - - ai = WirelessGetAssociationInfo(drv->wireless_ctx); - if (ai) { - wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo"); - CFRelease(ai); - } else { - wpa_printf(MSG_DEBUG, "OSX: Failed to get association info"); - } - - wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL); -} - - -static int wpa_driver_osx_associate(void *priv, - struct wpa_driver_associate_params *params) -{ - struct wpa_driver_osx_data *drv = priv; - WirelessError err; - CFDataRef ssid; - CFStringRef key; - int assoc_type; - - ssid = CFDataCreate(kCFAllocatorDefault, params->ssid, - params->ssid_len); - if (ssid == NULL) - return -1; - - /* TODO: support for WEP */ - if (params->key_mgmt_suite == KEY_MGMT_PSK) { - if (params->passphrase == NULL) - return -1; - key = CFStringCreateWithCString(kCFAllocatorDefault, - params->passphrase, - kCFStringEncodingISOLatin1); - if (key == NULL) { - CFRelease(ssid); - return -1; - } - } else - key = NULL; - - if (params->key_mgmt_suite == KEY_MGMT_NONE) - assoc_type = 0; - else - assoc_type = 4; - - wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)", - assoc_type, key); - err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key); - CFRelease(ssid); - if (key) - CFRelease(key); - if (err) { - wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x", - (unsigned int) err); - return -1; - } - - /* - * Driver is actually already associated; report association from an - * eloop callback. - */ - eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx); - eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv, - drv->ctx); - - return 0; -} - - -static int wpa_driver_osx_set_key(const char *ifname, void *priv, - enum wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, const u8 *seq, - size_t seq_len, const u8 *key, - size_t key_len) -{ - struct wpa_driver_osx_data *drv = priv; - WirelessError err; - - if (alg == WPA_ALG_WEP) { - err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len, - key); - if (err != 0) { - wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: " - "0x%08x", (unsigned int) err); - return -1; - } - - return 0; - } - - if (alg == WPA_ALG_PMK) { - err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key); - if (err != 0) { - wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: " - "0x%08x", (unsigned int) err); - return -1; - } - return 0; - } - - wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg); - return -1; -} - - -static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa) -{ - os_memset(capa, 0, sizeof(*capa)); - - capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; - capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 | - WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP; - capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | - WPA_DRIVER_AUTH_LEAP; - capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; - - return 0; -} - - -static void * wpa_driver_osx_init(void *ctx, const char *ifname) -{ - struct wpa_driver_osx_data *drv; - WirelessError err; - u8 enabled, power; - - if (!WirelessIsAvailable()) { - wpa_printf(MSG_ERROR, "OSX: No wireless interface available"); - return NULL; - } - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->ctx = ctx; - err = WirelessAttach(&drv->wireless_ctx, 0); - if (err) { - wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d", - (int) err); - os_free(drv); - return NULL; - } - - err = WirelessGetEnabled(drv->wireless_ctx, &enabled); - if (err) - wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x", - (unsigned int) err); - err = WirelessGetPower(drv->wireless_ctx, &power); - if (err) - wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x", - (unsigned int) err); - - wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power); - - if (!enabled) { - err = WirelessSetEnabled(drv->wireless_ctx, 1); - if (err) { - wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:" - " 0x%08x", (unsigned int) err); - WirelessDetach(drv->wireless_ctx); - os_free(drv); - return NULL; - } - } - - if (!power) { - err = WirelessSetPower(drv->wireless_ctx, 1); - if (err) { - wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: " - "0x%08x", (unsigned int) err); - WirelessDetach(drv->wireless_ctx); - os_free(drv); - return NULL; - } - } - - return drv; -} - - -static void wpa_driver_osx_deinit(void *priv) -{ - struct wpa_driver_osx_data *drv = priv; - WirelessError err; - - eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx); - eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx); - - err = WirelessSetPower(drv->wireless_ctx, 0); - if (err) { - wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: " - "0x%08x", (unsigned int) err); - } - - err = WirelessDetach(drv->wireless_ctx); - if (err) { - wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x", - (unsigned int) err); - } - - if (drv->scan_results) - CFRelease(drv->scan_results); - - os_free(drv); -} - - -const struct wpa_driver_ops wpa_driver_osx_ops = { - .name = "osx", - .desc = "Mac OS X Apple80211 driver", - .get_ssid = wpa_driver_osx_get_ssid, - .get_bssid = wpa_driver_osx_get_bssid, - .init = wpa_driver_osx_init, - .deinit = wpa_driver_osx_deinit, - .scan2 = wpa_driver_osx_scan, - .get_scan_results2 = wpa_driver_osx_get_scan_results, - .associate = wpa_driver_osx_associate, - .set_key = wpa_driver_osx_set_key, - .get_capa = wpa_driver_osx_get_capa, -}; diff --git a/src/drivers/driver_ralink.c b/src/drivers/driver_ralink.c deleted file mode 100644 index a1e27be..0000000 --- a/src/drivers/driver_ralink.c +++ /dev/null @@ -1,1498 +0,0 @@ -/* - * WPA Supplicant - driver interaction with Ralink Wireless Client - * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi> - * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - * - */ - -#include "includes.h" -#include <sys/ioctl.h> - -#include "wireless_copy.h" -#include "common.h" -#include "driver.h" -#include "l2_packet/l2_packet.h" -#include "eloop.h" -#include "common/ieee802_11_defs.h" -#include "priv_netlink.h" -#include "netlink.h" -#include "linux_ioctl.h" -#include "driver_ralink.h" - -static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx); - -#define MAX_SSID_LEN 32 - -struct wpa_driver_ralink_data { - void *ctx; - int ioctl_sock; - struct netlink_data *netlink; - char ifname[IFNAMSIZ + 1]; - u8 *assoc_req_ies; - size_t assoc_req_ies_len; - u8 *assoc_resp_ies; - size_t assoc_resp_ies_len; - int no_of_pmkid; - struct ndis_pmkid_entry *pmkid; - int we_version_compiled; - int ap_scan; - int scanning_done; - u8 g_driver_down; - BOOLEAN bAddWepKey; -}; - -static int ralink_set_oid(struct wpa_driver_ralink_data *drv, - unsigned short oid, char *data, int len) -{ - char *buf; - struct iwreq iwr; - - buf = os_zalloc(len); - if (buf == NULL) - return -1; - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.flags = oid; - iwr.u.data.flags |= OID_GET_SET_TOGGLE; - - if (data) - os_memcpy(buf, data, len); - - iwr.u.data.pointer = (caddr_t) buf; - iwr.u.data.length = len; - - if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) { - wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed", - __func__, oid, len); - os_free(buf); - return -1; - } - os_free(buf); - return 0; -} - -static int -ralink_get_new_driver_flag(struct wpa_driver_ralink_data *drv) -{ - struct iwreq iwr; - UCHAR enabled = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (UCHAR*) &enabled; - iwr.u.data.flags = RT_OID_NEW_DRIVER; - - if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) { - wpa_printf(MSG_DEBUG, "%s: failed", __func__); - return 0; - } - - return (enabled == 1) ? 1 : 0; -} - -static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid) -{ - struct wpa_driver_ralink_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - if (drv->g_driver_down == 1) - return -1; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) { - perror("ioctl[SIOCGIWAP]"); - ret = -1; - } - os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN); - - return ret; -} - -static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid) -{ - struct wpa_driver_ralink_data *drv = priv; -#if 0 - struct wpa_supplicant *wpa_s = drv->ctx; - struct wpa_ssid *entry; -#endif - int ssid_len; - u8 bssid[ETH_ALEN]; - u8 ssid_str[MAX_SSID_LEN]; - struct iwreq iwr; -#if 0 - int result = 0; -#endif - int ret = 0; -#if 0 - BOOLEAN ieee8021x_mode = FALSE; - BOOLEAN ieee8021x_required_key = FALSE; -#endif - - if (drv->g_driver_down == 1) - return -1; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.essid.pointer = (caddr_t) ssid; - iwr.u.essid.length = 32; - - if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { - perror("ioctl[SIOCGIWESSID]"); - ret = -1; - } else - ret = iwr.u.essid.length; - - if (ret <= 0) - return ret; - - ssid_len = ret; - os_memset(ssid_str, 0, MAX_SSID_LEN); - os_memcpy(ssid_str, ssid, ssid_len); - - if (drv->ap_scan == 0) { - /* Read BSSID form driver */ - if (wpa_driver_ralink_get_bssid(priv, bssid) < 0) { - wpa_printf(MSG_WARNING, "Could not read BSSID from " - "driver."); - return ret; - } - -#if 0 - entry = wpa_s->conf->ssid; - while (entry) { - if (!entry->disabled && ssid_len == entry->ssid_len && - os_memcmp(ssid_str, entry->ssid, ssid_len) == 0 && - (!entry->bssid_set || - os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) { - /* match the config of driver */ - result = 1; - break; - } - entry = entry->next; - } - - if (result) { - wpa_printf(MSG_DEBUG, "Ready to set 802.1x mode and " - "ieee_required_keys parameters to driver"); - - /* set 802.1x mode and ieee_required_keys parameter */ - if (entry->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { - if ((entry->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) - ieee8021x_required_key = TRUE; - ieee8021x_mode = TRUE; - } - - if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, (char *) &ieee8021x_mode, sizeof(BOOLEAN)) < 0) - { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set OID_802_11_SET_IEEE8021X(%d)", (int) ieee8021x_mode); - } - else - { - wpa_printf(MSG_DEBUG, "ieee8021x_mode is %s", ieee8021x_mode ? "TRUE" : "FALSE"); - } - - if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0) - { - wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", (int) ieee8021x_required_key); - } - else - { - wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d)", ieee8021x_required_key ? "TRUE" : "FALSE", - entry->eapol_flags); - } - } -#endif - } - - return ret; -} - -static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv, - const u8 *ssid, size_t ssid_len) -{ - NDIS_802_11_SSID *buf; - int ret = 0; - struct iwreq iwr; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - buf = os_zalloc(sizeof(NDIS_802_11_SSID)); - if (buf == NULL) - return -1; - os_memset(buf, 0, sizeof(buf)); - buf->SsidLength = ssid_len; - os_memcpy(buf->Ssid, ssid, ssid_len); - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - - iwr.u.data.flags = OID_802_11_SSID; - iwr.u.data.flags |= OID_GET_SET_TOGGLE; - iwr.u.data.pointer = (caddr_t) buf; - iwr.u.data.length = sizeof(NDIS_802_11_SSID); - - if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) { - perror("ioctl[RT_PRIV_IOCTL] -- OID_802_11_SSID"); - ret = -1; - } - os_free(buf); - return ret; -} - -static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv, - const u8 *data, size_t data_len) -{ - NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid; - size_t i; - union wpa_event_data event; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (data_len < 8) { - wpa_printf(MSG_DEBUG, "RALINK: Too short PMKID Candidate List " - "Event (len=%lu)", (unsigned long) data_len); - return; - } - pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data; - wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List Event - Version %d" - " NumCandidates %d", - (int) pmkid->Version, (int) pmkid->NumCandidates); - - if (pmkid->Version != 1) { - wpa_printf(MSG_DEBUG, "RALINK: Unsupported PMKID Candidate " - "List Version %d", (int) pmkid->Version); - return; - } - - if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) { - wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List " - "underflow"); - - return; - } - - - - os_memset(&event, 0, sizeof(event)); - for (i = 0; i < pmkid->NumCandidates; i++) { - PMKID_CANDIDATE *p = &pmkid->CandidateList[i]; - wpa_printf(MSG_DEBUG, "RALINK: %lu: " MACSTR " Flags 0x%x", - (unsigned long) i, MAC2STR(p->BSSID), - (int) p->Flags); - os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN); - event.pmkid_candidate.index = i; - event.pmkid_candidate.preauth = - p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED; - wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, - &event); - } -} - -static int wpa_driver_ralink_set_pmkid(struct wpa_driver_ralink_data *drv) -{ - int len, count, i, ret; - struct ndis_pmkid_entry *entry; - NDIS_802_11_PMKID *p; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - count = 0; - entry = drv->pmkid; - while (entry) { - count++; - if (count >= drv->no_of_pmkid) - break; - entry = entry->next; - } - len = 8 + count * sizeof(BSSID_INFO); - p = os_zalloc(len); - if (p == NULL) - return -1; - p->Length = len; - p->BSSIDInfoCount = count; - entry = drv->pmkid; - for (i = 0; i < count; i++) { - os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN); - os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16); - entry = entry->next; - } - wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", - (const u8 *) p, len); - ret = ralink_set_oid(drv, OID_802_11_PMKID, (char *) p, len); - os_free(p); - return ret; -} - -static int wpa_driver_ralink_add_pmkid(void *priv, const u8 *bssid, - const u8 *pmkid) -{ - struct wpa_driver_ralink_data *drv = priv; - struct ndis_pmkid_entry *entry, *prev; - - if (drv->g_driver_down == 1) - return -1; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (drv->no_of_pmkid == 0) - return 0; - - prev = NULL; - entry = drv->pmkid; - while (entry) { - if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0) - break; - prev = entry; - entry = entry->next; - } - - if (entry) { - /* Replace existing entry for this BSSID and move it into the - * beginning of the list. */ - os_memcpy(entry->pmkid, pmkid, 16); - if (prev) { - prev->next = entry->next; - entry->next = drv->pmkid; - drv->pmkid = entry; - } - } else { - entry = os_malloc(sizeof(*entry)); - if (entry) { - os_memcpy(entry->bssid, bssid, ETH_ALEN); - os_memcpy(entry->pmkid, pmkid, 16); - entry->next = drv->pmkid; - drv->pmkid = entry; - } - } - - return wpa_driver_ralink_set_pmkid(drv); -} - - -static int wpa_driver_ralink_remove_pmkid(void *priv, const u8 *bssid, - const u8 *pmkid) -{ - struct wpa_driver_ralink_data *drv = priv; - struct ndis_pmkid_entry *entry, *prev; - - if (drv->g_driver_down == 1) - return -1; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (drv->no_of_pmkid == 0) - return 0; - - entry = drv->pmkid; - prev = NULL; - drv->pmkid = NULL; - while (entry) { - if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 && - os_memcmp(entry->pmkid, pmkid, 16) == 0) { - if (prev) - prev->next = entry->next; - else - drv->pmkid = entry->next; - os_free(entry); - break; - } - prev = entry; - entry = entry->next; - } - return wpa_driver_ralink_set_pmkid(drv); -} - - -static int wpa_driver_ralink_flush_pmkid(void *priv) -{ - struct wpa_driver_ralink_data *drv = priv; - NDIS_802_11_PMKID p; - struct ndis_pmkid_entry *pmkid, *prev; - - if (drv->g_driver_down == 1) - return -1; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (drv->no_of_pmkid == 0) - return 0; - - pmkid = drv->pmkid; - drv->pmkid = NULL; - while (pmkid) { - prev = pmkid; - pmkid = pmkid->next; - os_free(prev); - } - - os_memset(&p, 0, sizeof(p)); - p.Length = 8; - p.BSSIDInfoCount = 0; - wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)", - (const u8 *) &p, 8); - return ralink_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8); -} - -static void -wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv, - void *ctx, char *custom) -{ - union wpa_event_data data; - u8 *req_ies = NULL, *resp_ies = NULL; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); - - os_memset(&data, 0, sizeof(data)); - /* Host AP driver */ - if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - /* receive a MICFAILURE report */ - data.michael_mic_failure.unicast = - os_strstr(custom, " unicast") != NULL; - /* TODO: parse parameters(?) */ - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); - } else if (os_strncmp(custom, "ASSOCINFO_ReqIEs=", 17) == 0) { - /* receive assoc. req. IEs */ - char *spos; - int bytes; - - spos = custom + 17; - /*get IE's length */ - /* - * bytes = strlen(spos); ==> bug, bytes may less than original - * size by using this way to get size. snowpin 20070312 - * if (!bytes) - * return; - */ - bytes = drv->assoc_req_ies_len; - - req_ies = os_malloc(bytes); - if (req_ies == NULL) - return; - os_memcpy(req_ies, spos, bytes); - data.assoc_info.req_ies = req_ies; - data.assoc_info.req_ies_len = bytes; - - /* skip the '\0' byte */ - spos += bytes + 1; - - data.assoc_info.resp_ies = NULL; - data.assoc_info.resp_ies_len = 0; - - if (os_strncmp(spos, " RespIEs=", 9) == 0) { - /* receive assoc. resp. IEs */ - spos += 9; - /* get IE's length */ - bytes = os_strlen(spos); - if (!bytes) - goto done; - - resp_ies = os_malloc(bytes); - if (resp_ies == NULL) - goto done; - os_memcpy(resp_ies, spos, bytes); - data.assoc_info.resp_ies = resp_ies; - data.assoc_info.resp_ies_len = bytes; - } - - wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); - - done: - /* free allocated memory */ - os_free(resp_ies); - os_free(req_ies); - } -} - -static void ralink_interface_up(struct wpa_driver_ralink_data *drv) -{ - union wpa_event_data event; - int enable_wpa_supplicant = 0; - drv->g_driver_down = 0; - os_memset(&event, 0, sizeof(event)); - os_snprintf(event.interface_status.ifname, - sizeof(event.interface_status.ifname), "%s", drv->ifname); - - event.interface_status.ievent = EVENT_INTERFACE_ADDED; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); - - if (drv->ap_scan == 1) - enable_wpa_supplicant = 1; - else - enable_wpa_supplicant = 2; - /* trigger driver support wpa_supplicant */ - if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, - (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0) - { - wpa_printf(MSG_INFO, "RALINK: Failed to set " - "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)", - (int) enable_wpa_supplicant); - wpa_printf(MSG_ERROR, "ralink. Driver does not support " - "wpa_supplicant"); - } -} - -static void -wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv, - void *ctx, char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom, *buf, *assoc_info_buf, *info_pos; -#if 0 - BOOLEAN ieee8021x_required_key = FALSE; -#endif - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - assoc_info_buf = info_pos = NULL; - pos = data; - end = data + len; - - while (pos + IW_EV_LCP_LEN <= end) { - /* Event data may be unaligned, so make a local, aligned copy - * before processing. */ - os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", - iwe->cmd, iwe->len); - if (iwe->len <= IW_EV_LCP_LEN) - return; - - custom = pos + IW_EV_POINT_LEN; - - if (drv->we_version_compiled > 18 && iwe->cmd == IWEVCUSTOM) { - /* WE-19 removed the pointer from struct iw_point */ - char *dpos = (char *) &iwe_buf.u.data.length; - int dlen = dpos - (char *) &iwe_buf; - os_memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); - custom += IW_EV_POINT_OFF; - } - - switch (iwe->cmd) { - case IWEVCUSTOM: - if (custom + iwe->u.data.length > end) - return; - buf = os_malloc(iwe->u.data.length + 1); - if (buf == NULL) - return; - os_memcpy(buf, custom, iwe->u.data.length); - buf[iwe->u.data.length] = '\0'; - - if (drv->ap_scan == 1) { - if ((iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) - || (iwe->u.data.flags == - RT_REQIE_EVENT_FLAG) || - (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) - || (iwe->u.data.flags == - RT_ASSOCINFO_EVENT_FLAG)) { - if (drv->scanning_done == 0) { - os_free(buf); - return; - } - } - } - - if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) { - wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); - wpa_printf(MSG_DEBUG, "Custom wireless event: " - "receive ASSOCIATED_EVENT !!!"); - } else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) { - wpa_printf(MSG_DEBUG, "Custom wireless event: " - "receive ReqIEs !!!"); - drv->assoc_req_ies = - os_malloc(iwe->u.data.length); - if (drv->assoc_req_ies == NULL) { - os_free(buf); - return; - } - - drv->assoc_req_ies_len = iwe->u.data.length; - os_memcpy(drv->assoc_req_ies, custom, - iwe->u.data.length); - } else if (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) { - wpa_printf(MSG_DEBUG, "Custom wireless event: " - "receive RespIEs !!!"); - drv->assoc_resp_ies = - os_malloc(iwe->u.data.length); - if (drv->assoc_resp_ies == NULL) { - os_free(drv->assoc_req_ies); - drv->assoc_req_ies = NULL; - os_free(buf); - return; - } - - drv->assoc_resp_ies_len = iwe->u.data.length; - os_memcpy(drv->assoc_resp_ies, custom, - iwe->u.data.length); - } else if (iwe->u.data.flags == - RT_ASSOCINFO_EVENT_FLAG) { - wpa_printf(MSG_DEBUG, "Custom wireless event: " - "receive ASSOCINFO_EVENT !!!"); - - assoc_info_buf = - os_zalloc(drv->assoc_req_ies_len + - drv->assoc_resp_ies_len + 1); - - if (assoc_info_buf == NULL) { - os_free(drv->assoc_req_ies); - drv->assoc_req_ies = NULL; - os_free(drv->assoc_resp_ies); - drv->assoc_resp_ies = NULL; - os_free(buf); - return; - } - - if (drv->assoc_req_ies) { - os_memcpy(assoc_info_buf, - drv->assoc_req_ies, - drv->assoc_req_ies_len); - } - info_pos = assoc_info_buf + - drv->assoc_req_ies_len; - if (drv->assoc_resp_ies) { - os_memcpy(info_pos, - drv->assoc_resp_ies, - drv->assoc_resp_ies_len); - } - assoc_info_buf[drv->assoc_req_ies_len + - drv->assoc_resp_ies_len] = '\0'; - wpa_driver_ralink_event_wireless_custom( - drv, ctx, assoc_info_buf); - os_free(drv->assoc_req_ies); - drv->assoc_req_ies = NULL; - os_free(drv->assoc_resp_ies); - drv->assoc_resp_ies = NULL; - os_free(assoc_info_buf); - } else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG) - { - wpa_printf(MSG_DEBUG, "Custom wireless event: " - "receive DISASSOCIATED_EVENT !!!"); - wpa_supplicant_event(ctx, EVENT_DISASSOC, - NULL); - } else if (iwe->u.data.flags == RT_PMKIDCAND_FLAG) { - wpa_printf(MSG_DEBUG, "Custom wireless event: " - "receive PMKIDCAND_EVENT !!!"); - wpa_driver_ralink_event_pmkid( - drv, (const u8 *) custom, - iwe->u.data.length); - } else if (iwe->u.data.flags == RT_INTERFACE_DOWN) { - drv->g_driver_down = 1; - eloop_terminate(); - } else if (iwe->u.data.flags == RT_INTERFACE_UP) { - ralink_interface_up(drv); - } else { - wpa_driver_ralink_event_wireless_custom( - drv, ctx, buf); - } - os_free(buf); - break; - } - - pos += iwe->len; - } -} - -static void -wpa_driver_ralink_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, - u8 *buf, size_t len) -{ - struct wpa_driver_ralink_data *drv = ctx; - int attrlen, rta_len; - struct rtattr *attr; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg)); - - attrlen = len; - wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen); - attr = (struct rtattr *) buf; - wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr)); - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len); - while (RTA_OK(attr, attrlen)) { - wpa_printf(MSG_DEBUG, "rta_type=%02x\n", attr->rta_type); - if (attr->rta_type == IFLA_WIRELESS) { - wpa_driver_ralink_event_wireless( - drv, ctx, - ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } - attr = RTA_NEXT(attr, attrlen); - wpa_hexdump(MSG_DEBUG, "attr3: ", - (u8 *) attr, sizeof(struct rtattr)); - } -} - -static int -ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv) -{ - struct iwreq iwr; - UINT we_version_compiled = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) &we_version_compiled; - iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED; - - if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) { - wpa_printf(MSG_DEBUG, "%s: failed", __func__); - return -1; - } - - drv->we_version_compiled = we_version_compiled; - - return 0; -} - -static void * wpa_driver_ralink_init(void *ctx, const char *ifname) -{ - int s; - struct wpa_driver_ralink_data *drv; - struct ifreq ifr; - UCHAR enable_wpa_supplicant = 0; - struct netlink_config *cfg; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - /* open socket to kernel */ - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - perror("socket"); - return NULL; - } - /* do it */ - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - - if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { - perror(ifr.ifr_name); - return NULL; - } - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - - drv->scanning_done = 1; - drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */ - drv->ctx = ctx; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - drv->ioctl_sock = s; - drv->g_driver_down = 0; - - cfg = os_zalloc(sizeof(*cfg)); - if (cfg == NULL) { - close(drv->ioctl_sock); - os_free(drv); - return NULL; - } - cfg->ctx = drv; - cfg->newlink_cb = wpa_driver_ralink_event_rtm_newlink; - drv->netlink = netlink_init(cfg); - if (drv->netlink == NULL) { - os_free(cfg); - close(drv->ioctl_sock); - os_free(drv); - return NULL; - } - - drv->no_of_pmkid = 4; /* Number of PMKID saved supported */ - - linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); - ralink_get_we_version_compiled(drv); - wpa_driver_ralink_flush_pmkid(drv); - - if (drv->ap_scan == 1) - enable_wpa_supplicant = 1; - else - enable_wpa_supplicant = 2; - /* trigger driver support wpa_supplicant */ - if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, - (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0) - { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)", - (int) enable_wpa_supplicant); - wpa_printf(MSG_ERROR, "RALINK: Driver does not support " - "wpa_supplicant"); - close(s); - close(drv->ioctl_sock); - os_free(drv); - return NULL; - } - - if (drv->ap_scan == 1) - drv->scanning_done = 0; - - return drv; -} - -static void wpa_driver_ralink_deinit(void *priv) -{ - struct wpa_driver_ralink_data *drv = priv; - UCHAR enable_wpa_supplicant; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - enable_wpa_supplicant = 0; - - if (drv->g_driver_down == 0) { - /* trigger driver disable wpa_supplicant support */ - if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, - (char *) &enable_wpa_supplicant, - sizeof(BOOLEAN)) < 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)", - (int) enable_wpa_supplicant); - } - - wpa_driver_ralink_flush_pmkid(drv); - - sleep(1); - /* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */ - } - - eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx); - netlink_deinit(drv->netlink); - close(drv->ioctl_sock); - os_free(drv); -} - -static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_driver_ralink_data *drv = eloop_ctx; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); - wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); - - drv->scanning_done = 1; - -} - -static int wpa_driver_ralink_scan(void *priv, - struct wpa_driver_scan_params *params) -{ - struct wpa_driver_ralink_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - if (drv->g_driver_down == 1) - return -1; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - -#if 0 - if (ssid_len > IW_ESSID_MAX_SIZE) { - wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", - __FUNCTION__, (unsigned long) ssid_len); - return -1; - } - - /* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */ -#endif - - if (ralink_set_oid(drv, RT_OID_WPS_PROBE_REQ_IE, - (char *) params->extra_ies, params->extra_ies_len) < - 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "RT_OID_WPS_PROBE_REQ_IE"); - } - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { - perror("ioctl[SIOCSIWSCAN]"); - ret = -1; - } - - /* Not all drivers generate "scan completed" wireless event, so try to - * read results after a timeout. */ - eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx); - eloop_register_timeout(4, 0, wpa_driver_ralink_scan_timeout, drv, - drv->ctx); - - drv->scanning_done = 0; - - return ret; -} - -static struct wpa_scan_results * -wpa_driver_ralink_get_scan_results(void *priv) -{ - struct wpa_driver_ralink_data *drv = priv; - UCHAR *buf = NULL; - size_t buf_len; - NDIS_802_11_BSSID_LIST_EX *wsr; - NDIS_WLAN_BSSID_EX *wbi; - struct iwreq iwr; - size_t ap_num; - u8 *pos; - struct wpa_scan_results *res; - - if (drv->g_driver_down == 1) - return NULL; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (drv->we_version_compiled >= 17) - buf_len = 8192; - else - buf_len = 4096; - - for (;;) { - buf = os_zalloc(buf_len); - iwr.u.data.length = buf_len; - if (buf == NULL) - return NULL; - - wsr = (NDIS_802_11_BSSID_LIST_EX *) buf; - - wsr->NumberOfItems = 0; - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (void *) buf; - iwr.u.data.flags = OID_802_11_BSSID_LIST; - - if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) == 0) - break; - - if (errno == E2BIG && buf_len < 65535) { - os_free(buf); - buf = NULL; - buf_len *= 2; - if (buf_len > 65535) - buf_len = 65535; /* 16-bit length field */ - wpa_printf(MSG_DEBUG, "Scan results did not fit - " - "trying larger buffer (%lu bytes)", - (unsigned long) buf_len); - } else { - perror("ioctl[RT_PRIV_IOCTL]"); - os_free(buf); - return NULL; - } - } - - res = os_zalloc(sizeof(*res)); - if (res == NULL) { - os_free(buf); - return NULL; - } - - res->res = os_zalloc(wsr->NumberOfItems * - sizeof(struct wpa_scan_res *)); - if (res->res == NULL) { - os_free(res); - os_free(buf); - return NULL; - } - - for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems; - ++ap_num) { - struct wpa_scan_res *r = NULL; - size_t extra_len = 0, var_ie_len = 0; - u8 *pos2; - - /* SSID data element */ - extra_len += 2 + wbi->Ssid.SsidLength; - var_ie_len = wbi->IELength - sizeof(NDIS_802_11_FIXED_IEs); - r = os_zalloc(sizeof(*r) + extra_len + var_ie_len); - if (r == NULL) - break; - res->res[res->num++] = r; - - wpa_printf(MSG_DEBUG, "SSID - %s", wbi->Ssid.Ssid); - /* get ie's */ - wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs", - (u8 *) &wbi->IEs[0], wbi->IELength); - - os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN); - - extra_len += (2 + wbi->Ssid.SsidLength); - r->ie_len = extra_len + var_ie_len; - pos2 = (u8 *) (r + 1); - - /* - * Generate a fake SSID IE since the driver did not report - * a full IE list. - */ - *pos2++ = WLAN_EID_SSID; - *pos2++ = wbi->Ssid.SsidLength; - os_memcpy(pos2, wbi->Ssid.Ssid, wbi->Ssid.SsidLength); - pos2 += wbi->Ssid.SsidLength; - - r->freq = (wbi->Configuration.DSConfig / 1000); - - pos = (u8 *) wbi + sizeof(*wbi) - 1; - - pos += sizeof(NDIS_802_11_FIXED_IEs) - 2; - os_memcpy(&(r->caps), pos, 2); - pos += 2; - - if (wbi->IELength > sizeof(NDIS_802_11_FIXED_IEs)) - os_memcpy(pos2, pos, var_ie_len); - - wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length); - } - - os_free(buf); - return res; -} - -static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv, - NDIS_802_11_AUTHENTICATION_MODE mode) -{ - NDIS_802_11_AUTHENTICATION_MODE auth_mode = mode; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (ralink_set_oid(drv, OID_802_11_AUTHENTICATION_MODE, - (char *) &auth_mode, sizeof(auth_mode)) < 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "OID_802_11_AUTHENTICATION_MODE (%d)", - (int) auth_mode); - return -1; - } - return 0; -} - -static int ralink_set_encr_type(struct wpa_driver_ralink_data *drv, - NDIS_802_11_WEP_STATUS encr_type) -{ - NDIS_802_11_WEP_STATUS wep_status = encr_type; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (ralink_set_oid(drv, OID_802_11_WEP_STATUS, - (char *) &wep_status, sizeof(wep_status)) < 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "OID_802_11_WEP_STATUS (%d)", - (int) wep_status); - return -1; - } - return 0; -} - - -static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv, - int key_idx, const u8 *addr, - const u8 *bssid, int pairwise) -{ - NDIS_802_11_REMOVE_KEY rkey; - NDIS_802_11_KEY_INDEX _index; - int res, res2; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - os_memset(&rkey, 0, sizeof(rkey)); - - rkey.Length = sizeof(rkey); - rkey.KeyIndex = key_idx; - - if (pairwise) - rkey.KeyIndex |= 1 << 30; - - os_memcpy(rkey.BSSID, bssid, ETH_ALEN); - - res = ralink_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey, - sizeof(rkey)); - - /* AlbertY@20060210 removed it */ - if (0 /* !pairwise */) { - res2 = ralink_set_oid(drv, OID_802_11_REMOVE_WEP, - (char *) &_index, sizeof(_index)); - } else - res2 = 0; - - if (res < 0 && res2 < 0) - return res; - return 0; -} - -static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv, - int pairwise, int key_idx, int set_tx, - const u8 *key, size_t key_len) -{ - NDIS_802_11_WEP *wep; - size_t len; - int res; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - len = 12 + key_len; - wep = os_zalloc(len); - if (wep == NULL) - return -1; - - wep->Length = len; - wep->KeyIndex = key_idx; - - if (set_tx) - wep->KeyIndex |= 0x80000000; - - wep->KeyLength = key_len; - os_memcpy(wep->KeyMaterial, key, key_len); - - wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_WEP", - (const u8 *) wep, len); - res = ralink_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len); - - os_free(wep); - - return res; -} - -static int wpa_driver_ralink_set_key(const char *ifname, void *priv, - enum wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) -{ - struct wpa_driver_ralink_data *drv = priv; - size_t len, i; - NDIS_802_11_KEY *nkey; - int res, pairwise; - u8 bssid[ETH_ALEN]; - - if (drv->g_driver_down == 1) - return -1; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - drv->bAddWepKey = FALSE; - - if (addr == NULL || is_broadcast_ether_addr(addr)) { - /* Group Key */ - pairwise = 0; - wpa_driver_ralink_get_bssid(drv, bssid); - } else { - /* Pairwise Key */ - pairwise = 1; - os_memcpy(bssid, addr, ETH_ALEN); - } - - if (alg == WPA_ALG_NONE || key_len == 0) { - return wpa_driver_ralink_remove_key(drv, key_idx, addr, bssid, - pairwise); - } - - if (alg == WPA_ALG_WEP) { - drv->bAddWepKey = TRUE; - return wpa_driver_ralink_add_wep(drv, pairwise, key_idx, - set_tx, key, key_len); - } - - len = 12 + 6 + 6 + 8 + key_len; - - nkey = os_zalloc(len); - if (nkey == NULL) - return -1; - - nkey->Length = len; - nkey->KeyIndex = key_idx; - - if (set_tx) - nkey->KeyIndex |= 1 << 31; - - if (pairwise) - nkey->KeyIndex |= 1 << 30; - - if (seq && seq_len) - nkey->KeyIndex |= 1 << 29; - - nkey->KeyLength = key_len; - os_memcpy(nkey->BSSID, bssid, ETH_ALEN); - - if (seq && seq_len) { - for (i = 0; i < seq_len; i++) - nkey->KeyRSC |= seq[i] << (i * 8); - } - if (alg == WPA_ALG_TKIP && key_len == 32) { - os_memcpy(nkey->KeyMaterial, key, 16); - os_memcpy(nkey->KeyMaterial + 16, key + 24, 8); - os_memcpy(nkey->KeyMaterial + 24, key + 16, 8); - } else { - os_memcpy(nkey->KeyMaterial, key, key_len); - } - - wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu " - "key_len=%lu", __FUNCTION__, alg, key_idx, set_tx, - (unsigned long) seq_len, (unsigned long) key_len); - - wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_KEY", - (const u8 *) nkey, len); - res = ralink_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len); - os_free(nkey); - - return res; -} - -static int wpa_driver_ralink_disassociate(void *priv, const u8 *addr, - int reason_code) -{ - struct wpa_driver_ralink_data *drv = priv; - - if (drv->g_driver_down == 1) - return -1; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - if (ralink_set_oid(drv, OID_802_11_DISASSOCIATE, " ", 4) < 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "OID_802_11_DISASSOCIATE"); - } - - return 0; -} - -static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr, - int reason_code) -{ - struct wpa_driver_ralink_data *drv = priv; - - wpa_printf(MSG_DEBUG, "g_driver_down = %d", drv->g_driver_down); - - if (drv->g_driver_down == 1) - return -1; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - if (ralink_get_new_driver_flag(drv) == 0) { - return wpa_driver_ralink_disassociate(priv, addr, reason_code); - } else { - MLME_DEAUTH_REQ_STRUCT mlme; - os_memset(&mlme, 0, sizeof(MLME_DEAUTH_REQ_STRUCT)); - mlme.Reason = reason_code; - os_memcpy(mlme.Addr, addr, MAC_ADDR_LEN); - return ralink_set_oid(drv, OID_802_11_DEAUTHENTICATION, - (char *) &mlme, - sizeof(MLME_DEAUTH_REQ_STRUCT)); - } -} - -static int wpa_driver_ralink_set_gen_ie(void *priv, const u8 *ie, - size_t ie_len) -{ - struct wpa_driver_ralink_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) ie; - iwr.u.data.length = ie_len; - - wpa_hexdump(MSG_DEBUG, "wpa_driver_ralink_set_gen_ie: ", - (u8 *) ie, ie_len); - - if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { - perror("ioctl[SIOCSIWGENIE]"); - ret = -1; - } - - return ret; -} - -static int -wpa_driver_ralink_associate(void *priv, - struct wpa_driver_associate_params *params) -{ - struct wpa_driver_ralink_data *drv = priv; - - NDIS_802_11_NETWORK_INFRASTRUCTURE mode; - NDIS_802_11_AUTHENTICATION_MODE auth_mode; - NDIS_802_11_WEP_STATUS encr; - BOOLEAN ieee8021xMode; - BOOLEAN ieee8021x_required_key = TRUE; - - if (drv->g_driver_down == 1) - return -1; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (params->mode == IEEE80211_MODE_IBSS) - mode = Ndis802_11IBSS; - else - mode = Ndis802_11Infrastructure; - - if (ralink_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE, - (char *) &mode, sizeof(mode)) < 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "OID_802_11_INFRASTRUCTURE_MODE (%d)", - (int) mode); - /* Try to continue anyway */ - } - - if (params->key_mgmt_suite == KEY_MGMT_WPS) { - UCHAR enable_wps = 0x80; - /* trigger driver support wpa_supplicant */ - if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, - (PCHAR) &enable_wps, sizeof(UCHAR)) < 0) { - wpa_printf(MSG_INFO, "RALINK: Failed to set " - "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)", - (int) enable_wps); - } - - wpa_driver_ralink_set_gen_ie(priv, params->wpa_ie, - params->wpa_ie_len); - - ralink_set_auth_mode(drv, Ndis802_11AuthModeOpen); - - ralink_set_encr_type(drv, Ndis802_11EncryptionDisabled); - } else { -#ifdef CONFIG_WPS - UCHAR enable_wpa_supplicant; - - if (drv->ap_scan == 1) - enable_wpa_supplicant = 0x01; - else - enable_wpa_supplicant = 0x02; - - /* trigger driver support wpa_supplicant */ - if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, - (PCHAR) &enable_wpa_supplicant, - sizeof(UCHAR)) < 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)", - (int) enable_wpa_supplicant); - } - - wpa_driver_ralink_set_gen_ie(priv, (u8 *) "", 0); -#endif /* CONFIG_WPS */ - - if (params->wpa_ie == NULL || params->wpa_ie_len == 0) { - if (params->auth_alg & WPA_AUTH_ALG_SHARED) { - if (params->auth_alg & WPA_AUTH_ALG_OPEN) - auth_mode = Ndis802_11AuthModeAutoSwitch; - else - auth_mode = Ndis802_11AuthModeShared; - } else - auth_mode = Ndis802_11AuthModeOpen; - } else if (params->wpa_ie[0] == WLAN_EID_RSN) { - if (params->key_mgmt_suite == KEY_MGMT_PSK) - auth_mode = Ndis802_11AuthModeWPA2PSK; - else - auth_mode = Ndis802_11AuthModeWPA2; - } else { - if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE) - auth_mode = Ndis802_11AuthModeWPANone; - else if (params->key_mgmt_suite == KEY_MGMT_PSK) - auth_mode = Ndis802_11AuthModeWPAPSK; - else - auth_mode = Ndis802_11AuthModeWPA; - } - - switch (params->pairwise_suite) { - case CIPHER_CCMP: - encr = Ndis802_11Encryption3Enabled; - break; - case CIPHER_TKIP: - encr = Ndis802_11Encryption2Enabled; - break; - case CIPHER_WEP40: - case CIPHER_WEP104: - encr = Ndis802_11Encryption1Enabled; - break; - case CIPHER_NONE: - if (params->group_suite == CIPHER_CCMP) - encr = Ndis802_11Encryption3Enabled; - else if (params->group_suite == CIPHER_TKIP) - encr = Ndis802_11Encryption2Enabled; - else - encr = Ndis802_11EncryptionDisabled; - break; - default: - encr = Ndis802_11EncryptionDisabled; - break; - } - - ralink_set_auth_mode(drv, auth_mode); - - /* notify driver that IEEE8021x mode is enabled */ - if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) { - ieee8021xMode = TRUE; - if (drv->bAddWepKey) - ieee8021x_required_key = FALSE; - } else - ieee8021xMode = FALSE; - - if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, - (char *) &ieee8021x_required_key, - sizeof(BOOLEAN)) < 0) { - wpa_printf(MSG_DEBUG, "ERROR: Failed to set " - "OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", - (int) ieee8021x_required_key); - } else { - wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s", - ieee8021x_required_key ? "TRUE" : "FALSE"); - } - - if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, - (char *) &ieee8021xMode, sizeof(BOOLEAN)) < - 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "OID_802_11_SET_IEEE8021X(%d)", - (int) ieee8021xMode); - } - - ralink_set_encr_type(drv, encr); - - if ((ieee8021xMode == FALSE) && - (encr == Ndis802_11Encryption1Enabled)) { - /* static WEP */ - int enabled = 0; - if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED, - (char *) &enabled, sizeof(enabled)) - < 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "OID_802_11_DROP_UNENCRYPTED(%d)", - (int) encr); - } - } - } - - return wpa_driver_ralink_set_ssid(drv, params->ssid, params->ssid_len); -} - -static int -wpa_driver_ralink_set_countermeasures(void *priv, int enabled) -{ - struct wpa_driver_ralink_data *drv = priv; - if (drv->g_driver_down == 1) - return -1; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); - return ralink_set_oid(drv, OID_SET_COUNTERMEASURES, (char *) &enabled, - sizeof(int)); -} - -const struct wpa_driver_ops wpa_driver_ralink_ops = { - .name = "ralink", - .desc = "Ralink Wireless Client driver", - .get_bssid = wpa_driver_ralink_get_bssid, - .get_ssid = wpa_driver_ralink_get_ssid, - .set_key = wpa_driver_ralink_set_key, - .init = wpa_driver_ralink_init, - .deinit = wpa_driver_ralink_deinit, - .set_countermeasures = wpa_driver_ralink_set_countermeasures, - .scan2 = wpa_driver_ralink_scan, - .get_scan_results2 = wpa_driver_ralink_get_scan_results, - .deauthenticate = wpa_driver_ralink_deauthenticate, - .disassociate = wpa_driver_ralink_disassociate, - .associate = wpa_driver_ralink_associate, - .add_pmkid = wpa_driver_ralink_add_pmkid, - .remove_pmkid = wpa_driver_ralink_remove_pmkid, - .flush_pmkid = wpa_driver_ralink_flush_pmkid, -}; diff --git a/src/drivers/driver_ralink.h b/src/drivers/driver_ralink.h deleted file mode 100644 index d13df28..0000000 --- a/src/drivers/driver_ralink.h +++ /dev/null @@ -1,383 +0,0 @@ -/* - * WPA Supplicant - driver_ralink exported functions - * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> - * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -// Ralink defined OIDs -#if WIRELESS_EXT <= 11 -#ifndef SIOCDEVPRIVATE -#define SIOCDEVPRIVATE 0x8BE0 -#endif -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif - -#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E) -#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02) - -// IEEE 802.11 OIDs & Ralink defined OIDs ****** - -// (RaConfig Set/QueryInform) ==> -#define OID_GET_SET_TOGGLE 0x8000 - -#define OID_802_11_ADD_WEP 0x0112 -#define OID_802_11_REMOVE_WEP 0x0113 -#define OID_802_11_DISASSOCIATE 0x0114 -#define OID_802_11_PRIVACY_FILTER 0x0118 -#define OID_802_11_ASSOCIATION_INFORMATION 0x011E -#define OID_802_11_BSSID_LIST_SCAN 0x0508 -#define OID_802_11_SSID 0x0509 -#define OID_802_11_BSSID 0x050A -#define OID_802_11_WEP_STATUS 0x0510 -#define OID_802_11_AUTHENTICATION_MODE 0x0511 -#define OID_802_11_INFRASTRUCTURE_MODE 0x0512 -#define OID_802_11_TX_POWER_LEVEL 0x0517 -#define OID_802_11_REMOVE_KEY 0x0519 -#define OID_802_11_ADD_KEY 0x0520 -#define OID_802_11_DEAUTHENTICATION 0x0526 -#define OID_802_11_DROP_UNENCRYPTED 0x0527 -#define OID_802_11_BSSID_LIST 0x0609 -#define OID_802_3_CURRENT_ADDRESS 0x060A -#define OID_SET_COUNTERMEASURES 0x0616 -#define OID_802_11_SET_IEEE8021X 0x0617 // For IEEE8021x mode -#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 // For DynamicWEP in IEEE802.1x mode -#define OID_802_11_PMKID 0x0620 -#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 // for trigger driver enable/disable wpa_supplicant support -#define RT_OID_WE_VERSION_COMPILED 0x0622 -#define RT_OID_NEW_DRIVER 0x0623 -#define RT_OID_WPS_PROBE_REQ_IE 0x0625 - -#define PACKED __attribute__ ((packed)) - -//wpa_supplicant event flags -#define RT_ASSOC_EVENT_FLAG 0x0101 -#define RT_DISASSOC_EVENT_FLAG 0x0102 -#define RT_REQIE_EVENT_FLAG 0x0103 -#define RT_RESPIE_EVENT_FLAG 0x0104 -#define RT_ASSOCINFO_EVENT_FLAG 0x0105 -#define RT_PMKIDCAND_FLAG 0x0106 -#define RT_INTERFACE_DOWN 0x0107 -#define RT_INTERFACE_UP 0x0108 - -// -// IEEE 802.11 Structures and definitions -// -// new types for Media Specific Indications - -#ifndef ULONG -#define CHAR char -#define INT int -#define SHORT int -#define UINT u32 -#undef ULONG -//#define ULONG u32 -#define ULONG unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */ -#define USHORT unsigned short -#define UCHAR unsigned char - -#define uint32 u32 -#define uint8 u8 - - -#define BOOLEAN u8 -//#define LARGE_INTEGER s64 -#define VOID void -#define LONG long -#define LONGLONG s64 -#define ULONGLONG u64 -typedef VOID *PVOID; -typedef CHAR *PCHAR; -typedef UCHAR *PUCHAR; -typedef USHORT *PUSHORT; -typedef LONG *PLONG; -typedef ULONG *PULONG; - -typedef union _LARGE_INTEGER { - struct { - ULONG LowPart; - LONG HighPart; - }vv; - struct { - ULONG LowPart; - LONG HighPart; - } u; - s64 QuadPart; -} LARGE_INTEGER; - -#endif - -#define NDIS_802_11_LENGTH_SSID 32 -#define NDIS_802_11_LENGTH_RATES 8 -#define NDIS_802_11_LENGTH_RATES_EX 16 -#define MAX_LEN_OF_SSID 32 -#define MAC_ADDR_LEN 6 - -typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; - -// mask for authentication/integrity fields -#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f - -#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 -#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 -#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 -#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E - -// Added new types for OFDM 5G and 2.4G -typedef enum _NDIS_802_11_NETWORK_TYPE -{ - Ndis802_11FH, - Ndis802_11DS, - Ndis802_11OFDM5, - Ndis802_11OFDM24, - Ndis802_11Automode, - Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound -} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; - -// -// Received Signal Strength Indication -// -typedef LONG NDIS_802_11_RSSI; // in dBm - -typedef struct _NDIS_802_11_CONFIGURATION_FH -{ - ULONG Length; // Length of structure - ULONG HopPattern; // As defined by 802.11, MSB set - ULONG HopSet; // to one if non-802.11 - ULONG DwellTime; // units are Kusec -} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; - -typedef struct _NDIS_802_11_CONFIGURATION -{ - ULONG Length; // Length of structure - ULONG BeaconPeriod; // units are Kusec - ULONG ATIMWindow; // units are Kusec - ULONG DSConfig; // Frequency, units are kHz - NDIS_802_11_CONFIGURATION_FH FHConfig; -} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; - -typedef ULONG NDIS_802_11_KEY_INDEX; -typedef ULONGLONG NDIS_802_11_KEY_RSC; - -// Key mapping keys require a BSSID -typedef struct _NDIS_802_11_KEY -{ - UINT Length; // Length of this structure - UINT KeyIndex; - UINT KeyLength; // length of key in bytes - NDIS_802_11_MAC_ADDRESS BSSID; - NDIS_802_11_KEY_RSC KeyRSC; - UCHAR KeyMaterial[1]; // variable length depending on above field -} NDIS_802_11_KEY, *PNDIS_802_11_KEY; - -typedef struct _NDIS_802_11_REMOVE_KEY -{ - UINT Length; // Length of this structure - UINT KeyIndex; - NDIS_802_11_MAC_ADDRESS BSSID; -} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; - -typedef struct PACKED _NDIS_802_11_WEP -{ - UINT Length; // Length of this structure - UINT KeyIndex; // 0 is the per-client key, 1-N are the - // global keys - UINT KeyLength; // length of key in bytes - UCHAR KeyMaterial[1];// variable length depending on above field -} NDIS_802_11_WEP, *PNDIS_802_11_WEP; - - -typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE -{ - Ndis802_11IBSS, - Ndis802_11Infrastructure, - Ndis802_11AutoUnknown, - Ndis802_11InfrastructureMax // Not a real value, defined as upper bound -} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; - -// PMKID Structures -typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; - -typedef struct _BSSID_INFO -{ - NDIS_802_11_MAC_ADDRESS BSSID; - NDIS_802_11_PMKID_VALUE PMKID; -} BSSID_INFO, *PBSSID_INFO; - -typedef struct _NDIS_802_11_PMKID -{ - ULONG Length; - ULONG BSSIDInfoCount; - BSSID_INFO BSSIDInfo[1]; -} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; - -//Added new types for PMKID Candidate lists. -typedef struct _PMKID_CANDIDATE { - NDIS_802_11_MAC_ADDRESS BSSID; - ULONG Flags; -} PMKID_CANDIDATE, *PPMKID_CANDIDATE; - -typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST -{ - ULONG Version; // Version of the structure - ULONG NumCandidates; // No. of pmkid candidates - PMKID_CANDIDATE CandidateList[1]; -} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST; - -//Flags for PMKID Candidate list structure -#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 - -// Add new authentication modes -typedef enum _NDIS_802_11_AUTHENTICATION_MODE -{ - Ndis802_11AuthModeOpen, - Ndis802_11AuthModeShared, - Ndis802_11AuthModeAutoSwitch, - Ndis802_11AuthModeWPA, - Ndis802_11AuthModeWPAPSK, - Ndis802_11AuthModeWPANone, - Ndis802_11AuthModeWPA2, - Ndis802_11AuthModeWPA2PSK, - Ndis802_11AuthModeMax // Not a real mode, defined as upper bound -} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE; - -typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates -typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates - -typedef struct PACKED _NDIS_802_11_SSID -{ - INT SsidLength; // length of SSID field below, in bytes; - // this can be zero. - UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field -} NDIS_802_11_SSID, *PNDIS_802_11_SSID; - - -typedef struct PACKED _NDIS_WLAN_BSSID -{ - ULONG Length; // Length of this structure - NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID - UCHAR Reserved[2]; - NDIS_802_11_SSID Ssid; // SSID - ULONG Privacy; // WEP encryption requirement - NDIS_802_11_RSSI Rssi; // receive signal - // strength in dBm - NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; - NDIS_802_11_CONFIGURATION Configuration; - NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; - NDIS_802_11_RATES SupportedRates; -} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID; - -typedef struct PACKED _NDIS_802_11_BSSID_LIST -{ - UINT NumberOfItems; // in list below, at least 1 - NDIS_WLAN_BSSID Bssid[1]; -} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST; - -// Added Capabilities, IELength and IEs for each BSSID -typedef struct PACKED _NDIS_WLAN_BSSID_EX -{ - ULONG Length; // Length of this structure - NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID - UCHAR Reserved[2]; - NDIS_802_11_SSID Ssid; // SSID - UINT Privacy; // WEP encryption requirement - NDIS_802_11_RSSI Rssi; // receive signal - // strength in dBm - NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; - NDIS_802_11_CONFIGURATION Configuration; - NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; - NDIS_802_11_RATES_EX SupportedRates; - ULONG IELength; - UCHAR IEs[1]; -} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; - -typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX -{ - UINT NumberOfItems; // in list below, at least 1 - NDIS_WLAN_BSSID_EX Bssid[1]; -} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX; - -typedef struct PACKED _NDIS_802_11_FIXED_IEs -{ - UCHAR Timestamp[8]; - USHORT BeaconInterval; - USHORT Capabilities; -} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs; - -// Added new encryption types -// Also aliased typedef to new name -typedef enum _NDIS_802_11_WEP_STATUS -{ - Ndis802_11WEPEnabled, - Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, - Ndis802_11WEPDisabled, - Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, - Ndis802_11WEPKeyAbsent, - Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, - Ndis802_11WEPNotSupported, - Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, - Ndis802_11Encryption2Enabled, - Ndis802_11Encryption2KeyAbsent, - Ndis802_11Encryption3Enabled, - Ndis802_11Encryption3KeyAbsent -} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, - NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; - -typedef enum _NDIS_802_11_RELOAD_DEFAULTS -{ - Ndis802_11ReloadWEPKeys -} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS; - -#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 -#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 -#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 - -#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 -#define NDIS_802_11_AI_RESFI_STATUSCODE 2 -#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 - -typedef struct _NDIS_802_11_AI_REQFI -{ - USHORT Capabilities; - USHORT ListenInterval; - NDIS_802_11_MAC_ADDRESS CurrentAPAddress; -} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; - -typedef struct _NDIS_802_11_AI_RESFI -{ - USHORT Capabilities; - USHORT StatusCode; - USHORT AssociationId; -} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; - -typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION -{ - ULONG Length; - USHORT AvailableRequestFixedIEs; - NDIS_802_11_AI_REQFI RequestFixedIEs; - ULONG RequestIELength; - ULONG OffsetRequestIEs; - USHORT AvailableResponseFixedIEs; - NDIS_802_11_AI_RESFI ResponseFixedIEs; - ULONG ResponseIELength; - ULONG OffsetResponseIEs; -} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; - -struct ndis_pmkid_entry { - struct ndis_pmkid_entry *next; - u8 bssid[ETH_ALEN]; - u8 pmkid[16]; -}; - -typedef struct _MLME_DEAUTH_REQ_STRUCT { - UCHAR Addr[MAC_ADDR_LEN]; - USHORT Reason; -} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT; diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c index c014b96..61b75b1 100644 --- a/src/drivers/driver_roboswitch.c +++ b/src/drivers/driver_roboswitch.c @@ -364,7 +364,7 @@ static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname) /* copy ifname and take a pointer to the second to last character */ sep = drv->ifname + os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2; - /* find the '.' seperating <interface> and <vlan> */ + /* find the '.' separating <interface> and <vlan> */ while (sep > drv->ifname && *sep != '.') sep--; if (sep <= drv->ifname) { wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in " diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 6bfa46d..f8e314b 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -89,7 +89,6 @@ struct wpa_driver_test_data { int use_associnfo; u8 assoc_wpa_ie[80]; size_t assoc_wpa_ie_len; - int use_mlme; int associated; u8 *probe_req_ie; size_t probe_req_ie_len; @@ -117,6 +116,7 @@ struct wpa_driver_test_data { u8 pending_action_dst[ETH_ALEN]; u8 pending_action_bssid[ETH_ALEN]; unsigned int pending_action_freq; + unsigned int pending_action_no_cck; unsigned int pending_listen_freq; unsigned int pending_listen_duration; int pending_p2p_scan; @@ -309,7 +309,7 @@ static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src, static int wpa_driver_test_send_mlme(void *priv, const u8 *data, - size_t data_len) + size_t data_len, int noack) { struct test_driver_bss *dbss = priv; struct wpa_driver_test_data *drv = dbss->drv; @@ -561,7 +561,7 @@ static void test_driver_scan(struct wpa_driver_test_data *drv, wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); #ifdef CONFIG_P2P if (drv->p2p) - p2p_probe_req_rx(drv->p2p, sa, ie, ielen); + p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen); #endif /* CONFIG_P2P */ } @@ -1102,13 +1102,6 @@ static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type, } -static int test_driver_valid_bss_mask(void *priv, const u8 *addr, - const u8 *mask) -{ - return 0; -} - - static int test_driver_set_ssid(void *priv, const u8 *buf, int len) { struct test_driver_bss *bss = priv; @@ -1232,6 +1225,7 @@ static void * test_driver_init(struct hostapd_data *hapd, return NULL; drv->ap = 1; bss = dl_list_first(&drv->bss, struct test_driver_bss, list); + drv->global = params->global_priv; bss->bss_ctx = hapd; os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN); @@ -1966,6 +1960,8 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) { os_memset(&event, 0, sizeof(event)); event.rx_probe_req.sa = mgmt->sa; + event.rx_probe_req.da = mgmt->da; + event.rx_probe_req.bssid = mgmt->bssid; event.rx_probe_req.ie = mgmt->u.probe_req.variable; event.rx_probe_req.ie_len = data_len - (mgmt->u.probe_req.variable - data); @@ -1974,6 +1970,7 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, #ifdef CONFIG_P2P if (drv->p2p) p2p_probe_req_rx(drv->p2p, mgmt->sa, + mgmt->da, mgmt->bssid, event.rx_probe_req.ie, event.rx_probe_req.ie_len); #endif /* CONFIG_P2P */ @@ -2028,7 +2025,7 @@ static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv, ielen = 0; drv->probe_from = from; drv->probe_from_len = fromlen; - p2p_probe_req_rx(drv->p2p, sa, ie, ielen); + p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen); drv->probe_from = NULL; } #endif /* CONFIG_P2P */ @@ -2390,13 +2387,6 @@ static int wpa_driver_test_set_param(void *priv, const char *param) drv->use_associnfo = 1; } -#ifdef CONFIG_CLIENT_MLME - if (os_strstr(param, "use_mlme=1")) { - wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME"); - drv->use_mlme = 1; - } -#endif /* CONFIG_CLIENT_MLME */ - if (os_strstr(param, "p2p_mgmt=1")) { wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P " "management"); @@ -2510,8 +2500,6 @@ static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; - if (drv->use_mlme) - capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME; if (drv->p2p) capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT; capa->flags |= WPA_DRIVER_FLAGS_AP; @@ -2541,50 +2529,6 @@ static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr, } -static int wpa_driver_test_set_channel(void *priv, - enum hostapd_hw_mode phymode, - int chan, int freq) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d", - __func__, phymode, chan, freq); - drv->current_freq = freq; - return 0; -} - - -static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr, - const u8 *supp_rates, - size_t supp_rates_len) -{ - wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr)); - return 0; -} - - -static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr) -{ - wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr)); - return 0; -} - - -static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid, - size_t ssid_len) -{ - wpa_printf(MSG_DEBUG, "%s", __func__); - return 0; -} - - -static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid) -{ - wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid)); - return 0; -} - - static void * wpa_driver_test_global_init(void) { struct wpa_driver_test_global *global; @@ -2727,7 +2671,8 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq, unsigned int wait, const u8 *dst, const u8 *src, const u8 *bssid, - const u8 *data, size_t data_len) + const u8 *data, size_t data_len, + int no_cck) { struct test_driver_bss *dbss = priv; struct wpa_driver_test_data *drv = dbss->drv; @@ -2760,7 +2705,7 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq, os_memcpy(hdr->addr2, src, ETH_ALEN); os_memcpy(hdr->addr3, bssid, ETH_ALEN); - ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len); + ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len, 0); os_free(buf); return ret; } @@ -2770,7 +2715,6 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq, static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_test_data *drv = eloop_ctx; - int res; if (drv->pending_action_tx == NULL) return; @@ -2783,12 +2727,13 @@ static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx) } wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to " MACSTR, MAC2STR(drv->pending_action_dst)); - res = wpa_driver_test_send_action(drv, drv->pending_action_freq, 0, - drv->pending_action_dst, - drv->pending_action_src, - drv->pending_action_bssid, - wpabuf_head(drv->pending_action_tx), - wpabuf_len(drv->pending_action_tx)); + wpa_driver_test_send_action(drv, drv->pending_action_freq, 0, + drv->pending_action_dst, + drv->pending_action_src, + drv->pending_action_bssid, + wpabuf_head(drv->pending_action_tx), + wpabuf_len(drv->pending_action_tx), + drv->pending_action_no_cck); } #endif /* CONFIG_P2P */ @@ -2980,6 +2925,7 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, int ret; struct wpabuf *wps_ie, *ies; int social_channels[] = { 2412, 2437, 2462, 0, 0 }; + size_t ielen; wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)", __func__, type, freq); @@ -3001,7 +2947,8 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, if (wps_ie == NULL) return -1; - ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100); + ielen = p2p_scan_ie_buf_len(drv->p2p); + ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); if (ies == NULL) { wpabuf_free(wps_ie); return -1; @@ -3069,6 +3016,7 @@ static int test_send_action(void *ctx, unsigned int freq, const u8 *dst, os_memcpy(drv->pending_action_dst, dst, ETH_ALEN); os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN); drv->pending_action_freq = freq; + drv->pending_action_no_cck = 1; if (drv->off_channel_freq == freq) { /* Already on requested channel; send immediately */ @@ -3248,7 +3196,8 @@ static void test_sd_response(void *ctx, const u8 *sa, u16 update_indic, static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, const u8 *dev_addr, const u8 *pri_dev_type, const char *dev_name, u16 supp_config_methods, - u8 dev_capab, u8 group_capab) + u8 dev_capab, u8 group_capab, + const u8 *group_id, size_t group_id_len) { wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)", __func__, MAC2STR(peer), config_methods); @@ -3343,7 +3292,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = { .get_hw_feature_data = wpa_driver_test_get_hw_feature_data, .if_add = test_driver_if_add, .if_remove = test_driver_if_remove, - .valid_bss_mask = test_driver_valid_bss_mask, .hapd_set_ssid = test_driver_set_ssid, .set_privacy = test_driver_set_privacy, .set_sta_vlan = test_driver_set_sta_vlan, @@ -3362,11 +3310,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = { .get_mac_addr = wpa_driver_test_get_mac_addr, .send_eapol = wpa_driver_test_send_eapol, .mlme_setprotection = wpa_driver_test_mlme_setprotection, - .set_channel = wpa_driver_test_set_channel, - .set_ssid = wpa_driver_test_set_ssid, - .set_bssid = wpa_driver_test_set_bssid, - .mlme_add_sta = wpa_driver_test_mlme_add_sta, - .mlme_remove_sta = wpa_driver_test_mlme_remove_sta, .get_scan_results2 = wpa_driver_test_get_scan_results2, .global_init = wpa_driver_test_global_init, .global_deinit = wpa_driver_test_global_deinit, diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index 001716e..381cb3e 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -25,7 +25,7 @@ #include <fcntl.h> #include <net/if_arp.h> -#include "wireless_copy.h" +#include "linux_wext.h" #include "common.h" #include "eloop.h" #include "common/ieee802_11_defs.h" @@ -37,6 +37,9 @@ #include "driver.h" #include "driver_wext.h" +#ifdef ANDROID +#include "android_drv.h" +#endif /* ANDROID */ static int wpa_driver_wext_flush_pmkid(void *priv); static int wpa_driver_wext_get_range(void *priv); @@ -842,12 +845,13 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname) } drv->mlme_sock = -1; + #ifdef ANDROID drv->errors = 0; drv->driver_is_started = TRUE; drv->skip_disconnect = 0; drv->bgscan_enabled = 0; -#endif +#endif /* ANDROID */ if (wpa_driver_wext_finish_drv_init(drv) < 0) goto err3; @@ -1416,7 +1420,7 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res, tmp[res->num++] = r; res->res = tmp; } - + /** * wpa_driver_wext_get_scan_results - Fetch the latest scan results @@ -1426,7 +1430,7 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res, struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv) { struct wpa_driver_wext_data *drv = priv; - size_t ap_num = 0, len; + size_t len; int first; u8 *res_buf; struct iw_event iwe_buf, *iwe = &iwe_buf; @@ -1438,7 +1442,6 @@ struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv) if (res_buf == NULL) return NULL; - ap_num = 0; first = 1; res = os_zalloc(sizeof(*res)); @@ -1868,8 +1871,10 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) { struct iwreq iwr; const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; +#ifndef ANDROID u8 ssid[32]; int i; +#endif /* ANDROID */ /* * Only force-disconnect when the card is in infrastructure mode, @@ -1884,40 +1889,39 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) } if (iwr.u.mode == IW_MODE_INFRA) { + /* Clear the BSSID selection */ + if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) { + wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID " + "selection on disconnect"); + } + +#ifndef ANDROID if (drv->cfg80211) { /* * cfg80211 supports SIOCSIWMLME commands, so there is * no need for the random SSID hack, but clear the - * BSSID and SSID. + * SSID. */ - if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 || -#ifdef ANDROID - 0) { -#else - wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { -#endif + if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { wpa_printf(MSG_DEBUG, "WEXT: Failed to clear " - "to disconnect"); + "SSID on disconnect"); } return; } + /* - * Clear the BSSID selection and set a random SSID to make sure - * the driver will not be trying to associate with something - * even if it does not understand SIOCSIWMLME commands (or - * tries to associate automatically after deauth/disassoc). + * Set a random SSID to make sure the driver will not be trying + * to associate with something even if it does not understand + * SIOCSIWMLME commands (or tries to associate automatically + * after deauth/disassoc). */ for (i = 0; i < 32; i++) ssid[i] = rand() & 0xFF; - if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 || -#ifdef ANDROID - 0) { -#else - wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) { -#endif + if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) { wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " - "BSSID/SSID to disconnect"); + "SSID to disconnect"); } +#endif /* ANDROID */ } } @@ -2350,6 +2354,129 @@ static const char * wext_get_radio_name(void *priv) } +#ifdef ANDROID + +static int android_wext_cmd(struct wpa_driver_wext_data *drv, const char *cmd) +{ + struct iwreq iwr; + char buf[MAX_DRV_CMD_SIZE]; + int ret; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + + os_memset(buf, 0, sizeof(buf)); + os_strlcpy(buf, cmd, sizeof(buf)); + + iwr.u.data.pointer = buf; + iwr.u.data.length = sizeof(buf); + + ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret, + cmd); + drv->errors++; + if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv->errors = 0; + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE + "HANGED"); + } + return ret; + } + + drv->errors = 0; + return 0; +} + + +static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params, + u32 interval) +{ + struct wpa_driver_wext_data *drv = priv; + struct iwreq iwr; + int ret = 0, i = 0, bp; + char buf[WEXT_PNO_MAX_COMMAND_SIZE]; + + bp = WEXT_PNOSETUP_HEADER_SIZE; + os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); + buf[bp++] = WEXT_PNO_TLV_PREFIX; + buf[bp++] = WEXT_PNO_TLV_VERSION; + buf[bp++] = WEXT_PNO_TLV_SUBVERSION; + buf[bp++] = WEXT_PNO_TLV_RESERVED; + + while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) { + /* + * Check that there is enough space needed for 1 more SSID, the + * other sections and null termination. + */ + if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE + + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf)) + break; + + wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan", + params->ssids[i].ssid, + params->ssids[i].ssid_len); + buf[bp++] = WEXT_PNO_SSID_SECTION; + buf[bp++] = params->ssids[i].ssid_len; + os_memcpy(&buf[bp], params->ssids[i].ssid, + params->ssids[i].ssid_len); + bp += params->ssids[i].ssid_len; + i++; + } + + buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; + /* TODO: consider using interval parameter (interval in msec) instead + * of hardcoded value here */ + os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", + WEXT_PNO_SCAN_INTERVAL); + bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; + + buf[bp++] = WEXT_PNO_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", + WEXT_PNO_REPEAT); + bp += WEXT_PNO_REPEAT_LENGTH; + + buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", + WEXT_PNO_MAX_REPEAT); + bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + iwr.u.data.pointer = buf; + iwr.u.data.length = bp; + + ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr); + if (ret < 0) { + wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", + ret); + drv->errors++; + if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv->errors = 0; + wpa_msg(drv->ctx, MSG_INFO, + WPA_EVENT_DRIVER_STATE "HANGED"); + } + return ret; + } + + drv->errors = 0; + drv->bgscan_enabled = 1; + + return android_wext_cmd(drv, "PNOFORCE 1"); +} + + +static int wext_stop_sched_scan(void *priv) +{ + struct wpa_driver_wext_data *drv = priv; + drv->bgscan_enabled = 0; + return android_wext_cmd(drv, "PNOFORCE 0"); +} + +#endif /* ANDROID */ + + const struct wpa_driver_ops wpa_driver_wext_ops = { .name = "wext", .desc = "Linux wireless extensions (generic)", @@ -2371,7 +2498,7 @@ const struct wpa_driver_ops wpa_driver_wext_ops = { .set_operstate = wpa_driver_wext_set_operstate, .get_radio_name = wext_get_radio_name, #ifdef ANDROID - .signal_poll = wpa_driver_signal_poll, - .driver_cmd = wpa_driver_wext_driver_cmd, -#endif + .sched_scan = wext_sched_scan, + .stop_sched_scan = wext_stop_sched_scan, +#endif /* ANDROID */ }; diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h index 51e4d98..03df8e4 100644 --- a/src/drivers/driver_wext.h +++ b/src/drivers/driver_wext.h @@ -50,12 +50,13 @@ struct wpa_driver_wext_data { int cfg80211; /* whether driver is using cfg80211 */ u8 max_level; + #ifdef ANDROID int errors; int driver_is_started; int skip_disconnect; int bgscan_enabled; -#endif +#endif /* ANDROID */ }; int wpa_driver_wext_get_bssid(void *priv, u8 *bssid); @@ -90,9 +91,4 @@ int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, int wpa_driver_wext_cipher2wext(int cipher); int wpa_driver_wext_keymgmt2wext(int keymgmt); -#ifdef ANDROID -#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE " -#define WEXT_CSCAN_AMOUNT 9 -#endif - #endif /* DRIVER_WEXT_H */ diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c index b710778..667ea22 100644 --- a/src/drivers/drivers.c +++ b/src/drivers/drivers.c @@ -27,9 +27,6 @@ extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ #ifdef CONFIG_DRIVER_MADWIFI extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */ #endif /* CONFIG_DRIVER_MADWIFI */ -#ifdef CONFIG_DRIVER_BROADCOM -extern struct wpa_driver_ops wpa_driver_broadcom_ops; /* driver_broadcom.c */ -#endif /* CONFIG_DRIVER_BROADCOM */ #ifdef CONFIG_DRIVER_BSD extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ #endif /* CONFIG_DRIVER_BSD */ @@ -42,15 +39,6 @@ extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */ #ifdef CONFIG_DRIVER_TEST extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */ #endif /* CONFIG_DRIVER_TEST */ -#ifdef CONFIG_DRIVER_RALINK -extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */ -#endif /* CONFIG_DRIVER_RALINK */ -#ifdef CONFIG_DRIVER_OSX -extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */ -#endif /* CONFIG_DRIVER_OSX */ -#ifdef CONFIG_DRIVER_IPHONE -extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */ -#endif /* CONFIG_DRIVER_IPHONE */ #ifdef CONFIG_DRIVER_ROBOSWITCH /* driver_roboswitch.c */ extern struct wpa_driver_ops wpa_driver_roboswitch_ops; @@ -77,9 +65,6 @@ struct wpa_driver_ops *wpa_drivers[] = #ifdef CONFIG_DRIVER_MADWIFI &wpa_driver_madwifi_ops, #endif /* CONFIG_DRIVER_MADWIFI */ -#ifdef CONFIG_DRIVER_BROADCOM - &wpa_driver_broadcom_ops, -#endif /* CONFIG_DRIVER_BROADCOM */ #ifdef CONFIG_DRIVER_BSD &wpa_driver_bsd_ops, #endif /* CONFIG_DRIVER_BSD */ @@ -92,15 +77,6 @@ struct wpa_driver_ops *wpa_drivers[] = #ifdef CONFIG_DRIVER_TEST &wpa_driver_test_ops, #endif /* CONFIG_DRIVER_TEST */ -#ifdef CONFIG_DRIVER_RALINK - &wpa_driver_ralink_ops, -#endif /* CONFIG_DRIVER_RALINK */ -#ifdef CONFIG_DRIVER_OSX - &wpa_driver_osx_ops, -#endif /* CONFIG_DRIVER_OSX */ -#ifdef CONFIG_DRIVER_IPHONE - &wpa_driver_iphone_ops, -#endif /* CONFIG_DRIVER_IPHONE */ #ifdef CONFIG_DRIVER_ROBOSWITCH &wpa_driver_roboswitch_ops, #endif /* CONFIG_DRIVER_ROBOSWITCH */ diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak index ebf39c8..0cc81f9 100644 --- a/src/drivers/drivers.mak +++ b/src/drivers/drivers.mak @@ -12,29 +12,11 @@ DRV_AP_LIBS = ##### COMMON DRIVERS -ifdef CONFIG_DRIVER_HOSTAP -DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP -DRV_OBJS += ../src/drivers/driver_hostap.o -CONFIG_WIRELESS_EXTENSION=y -NEED_AP_MLME=y -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - ifdef CONFIG_DRIVER_WIRED DRV_CFLAGS += -DCONFIG_DRIVER_WIRED DRV_OBJS += ../src/drivers/driver_wired.o endif -ifdef CONFIG_DRIVER_MADWIFI -DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI -DRV_OBJS += ../src/drivers/driver_madwifi.o -CONFIG_WIRELESS_EXTENSION=y -CONFIG_L2_PACKET=linux -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - ifdef CONFIG_DRIVER_NL80211 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 DRV_OBJS += ../src/drivers/driver_nl80211.o @@ -44,15 +26,22 @@ NEED_AP_MLME=y NEED_NETLINK=y NEED_LINUX_IOCTL=y NEED_RFKILL=y -ifdef CONFIG_LIBNL_TINY -DRV_LIBS += -lnl-tiny + +ifdef CONFIG_LIBNL32 + DRV_LIBS += -lnl-3 + DRV_LIBS += -lnl-genl-3 + DRV_CFLAGS += -DCONFIG_LIBNL20 else -DRV_LIBS += -lnl -endif + ifdef CONFIG_LIBNL_TINY + DRV_LIBS += -lnl-tiny + else + DRV_LIBS += -lnl + endif -ifdef CONFIG_LIBNL20 -DRV_LIBS += -lnl-genl -DRV_CFLAGS += -DCONFIG_LIBNL20 + ifdef CONFIG_LIBNL20 + DRV_LIBS += -lnl-genl + DRV_CFLAGS += -DCONFIG_LIBNL20 + endif endif endif @@ -79,6 +68,24 @@ endif ##### PURE AP DRIVERS +ifdef CONFIG_DRIVER_HOSTAP +DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP +DRV_AP_OBJS += ../src/drivers/driver_hostap.o +CONFIG_WIRELESS_EXTENSION=y +NEED_AP_MLME=y +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + +ifdef CONFIG_DRIVER_MADWIFI +DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI +DRV_AP_OBJS += ../src/drivers/driver_madwifi.o +CONFIG_WIRELESS_EXTENSION=y +CONFIG_L2_PACKET=linux +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + ifdef CONFIG_DRIVER_ATHEROS DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS DRV_AP_OBJS += ../src/drivers/driver_atheros.o @@ -97,18 +104,6 @@ NEED_LINUX_IOCTL=y NEED_RFKILL=y endif -ifdef CONFIG_DRIVER_RALINK -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK -DRV_WPA_OBJS += ../src/drivers/driver_ralink.o -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - -ifdef CONFIG_DRIVER_BROADCOM -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM -DRV_WPA_OBJS += ../src/drivers/driver_broadcom.o -endif - ifdef CONFIG_DRIVER_NDIS DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS DRV_WPA_OBJS += ../src/drivers/driver_ndis.o @@ -124,20 +119,6 @@ DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO endif endif -ifdef CONFIG_DRIVER_OSX -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX -DRV_WPA_OBJS += ../src/drivers/driver_osx.o -DRV_WPA_LDFLAGS += -framework CoreFoundation -DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211 -endif - -ifdef CONFIG_DRIVER_IPHONE -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE -DRV_WPA_OBJS += ../src/drivers/driver_iphone.o -DRV_WPA_OBJS += ../src/drivers/MobileApple80211.o -DRV_WPA_LDFLAGS += -framework CoreFoundation -endif - ifdef CONFIG_DRIVER_ROBOSWITCH DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk index c690e1c..1d7129c 100644 --- a/src/drivers/drivers.mk +++ b/src/drivers/drivers.mk @@ -12,29 +12,11 @@ DRV_AP_LIBS = ##### COMMON DRIVERS -ifdef CONFIG_DRIVER_HOSTAP -DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP -DRV_OBJS += src/drivers/driver_hostap.c -CONFIG_WIRELESS_EXTENSION=y -NEED_AP_MLME=y -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - ifdef CONFIG_DRIVER_WIRED DRV_CFLAGS += -DCONFIG_DRIVER_WIRED DRV_OBJS += src/drivers/driver_wired.c endif -ifdef CONFIG_DRIVER_MADWIFI -DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI -DRV_OBJS += src/drivers/driver_madwifi.c -CONFIG_WIRELESS_EXTENSION=y -CONFIG_L2_PACKET=linux -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - ifdef CONFIG_DRIVER_NL80211 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 DRV_OBJS += src/drivers/driver_nl80211.c @@ -44,15 +26,22 @@ NEED_AP_MLME=y NEED_NETLINK=y NEED_LINUX_IOCTL=y NEED_RFKILL=y -ifdef CONFIG_LIBNL_TINY -DRV_LIBS += -lnl-tiny + +ifdef CONFIG_LIBNL32 + DRV_LIBS += -lnl-3 + DRV_LIBS += -lnl-genl-3 + DRV_CFLAGS += -DCONFIG_LIBNL20 else -DRV_LIBS += -lnl -endif + ifdef CONFIG_LIBNL_TINY + DRV_LIBS += -lnl-tiny + else + DRV_LIBS += -lnl + endif -ifdef CONFIG_LIBNL20 -DRV_LIBS += -lnl-genl -DRV_CFLAGS += -DCONFIG_LIBNL20 + ifdef CONFIG_LIBNL20 + DRV_LIBS += -lnl-genl + DRV_CFLAGS += -DCONFIG_LIBNL20 + endif endif endif @@ -79,6 +68,24 @@ endif ##### PURE AP DRIVERS +ifdef CONFIG_DRIVER_HOSTAP +DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP +DRV_AP_OBJS += src/drivers/driver_hostap.c +CONFIG_WIRELESS_EXTENSION=y +NEED_AP_MLME=y +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + +ifdef CONFIG_DRIVER_MADWIFI +DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI +DRV_AP_OBJS += src/drivers/driver_madwifi.c +CONFIG_WIRELESS_EXTENSION=y +CONFIG_L2_PACKET=linux +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + ifdef CONFIG_DRIVER_ATHEROS DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS DRV_AP_OBJS += src/drivers/driver_atheros.c @@ -97,18 +104,6 @@ NEED_LINUX_IOCTL=y NEED_RFKILL=y endif -ifdef CONFIG_DRIVER_RALINK -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK -DRV_WPA_OBJS += src/drivers/driver_ralink.c -NEED_NETLINK=y -NEED_LINUX_IOCTL=y -endif - -ifdef CONFIG_DRIVER_BROADCOM -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM -DRV_WPA_OBJS += src/drivers/driver_broadcom.c -endif - ifdef CONFIG_DRIVER_NDIS DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS DRV_WPA_OBJS += src/drivers/driver_ndis.c @@ -124,20 +119,6 @@ DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO endif endif -ifdef CONFIG_DRIVER_OSX -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX -DRV_WPA_OBJS += src/drivers/driver_osx.c -DRV_WPA_LDFLAGS += -framework CoreFoundation -DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211 -endif - -ifdef CONFIG_DRIVER_IPHONE -DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE -DRV_WPA_OBJS += src/drivers/driver_iphone.c -DRV_WPA_OBJS += src/drivers/MobileApple80211.c -DRV_WPA_LDFLAGS += -framework CoreFoundation -endif - ifdef CONFIG_DRIVER_ROBOSWITCH DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH DRV_WPA_OBJS += src/drivers/driver_roboswitch.c diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c index 0d6cf54..d7501cf 100644 --- a/src/drivers/linux_ioctl.c +++ b/src/drivers/linux_ioctl.c @@ -24,6 +24,7 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up) { struct ifreq ifr; + int ret; if (sock < 0) return -1; @@ -32,9 +33,10 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up) os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) { + ret = errno ? -errno : -999; wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s", ifname, strerror(errno)); - return -1; + return ret; } if (dev_up) { @@ -48,15 +50,38 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up) } if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) { + ret = errno ? -errno : -999; wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s", ifname, strerror(errno)); - return -1; + return ret; } return 0; } +int linux_iface_up(int sock, const char *ifname) +{ + struct ifreq ifr; + int ret; + + if (sock < 0) + return -1; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + + if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) { + ret = errno ? -errno : -999; + wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s", + ifname, strerror(errno)); + return ret; + } + + return !!(ifr.ifr_flags & IFF_UP); +} + + int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr) { struct ifreq ifr; diff --git a/src/drivers/linux_ioctl.h b/src/drivers/linux_ioctl.h index a555738..e0bf673 100644 --- a/src/drivers/linux_ioctl.h +++ b/src/drivers/linux_ioctl.h @@ -16,6 +16,7 @@ #define LINUX_IOCTL_H int linux_set_iface_flags(int sock, const char *ifname, int dev_up); +int linux_iface_up(int sock, const char *ifname); int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr); int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr); int linux_br_add(int sock, const char *brname); diff --git a/src/drivers/linux_wext.h b/src/drivers/linux_wext.h new file mode 100644 index 0000000..b6eea68 --- /dev/null +++ b/src/drivers/linux_wext.h @@ -0,0 +1,51 @@ +/* + * Driver interaction with generic Linux Wireless Extensions + * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef LINUX_WEXT_H +#define LINUX_WEXT_H + +#ifndef ANDROID + +/* + * Avoid including other kernel header to avoid conflicts with C library + * headers. + */ +#define _LINUX_TYPES_H +#define _LINUX_SOCKET_H +#define _LINUX_IF_H + +#include <sys/types.h> +#include <net/if.h> +typedef __uint32_t __u32; +typedef __int32_t __s32; +typedef __uint16_t __u16; +typedef __int16_t __s16; +typedef __uint8_t __u8; +#ifndef __user +#define __user +#endif /* __user */ + +#endif /* ANDROID */ + +#include <linux/wireless.h> + +#ifndef IW_ENCODE_ALG_PMK +#define IW_ENCODE_ALG_PMK 4 +#endif + +#ifndef IW_ENC_CAPA_4WAY_HANDSHAKE +#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 +#endif + +#endif /* LINUX_WEXT_H */ diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c index ad15b1d..6778907 100644 --- a/src/drivers/netlink.c +++ b/src/drivers/netlink.c @@ -34,7 +34,7 @@ static void netlink_receive_link(struct netlink_data *netlink, if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg)) return; cb(netlink->cfg->ctx, NLMSG_DATA(h), - NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)), + (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)), NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg))); } diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index 7483a89..f9261c2 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -6,7 +6,7 @@ * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2008 Michael Wu <flamingice@sourmilk.net> * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com> - * Copyright 2008 Michael Buesch <mb@bu3sch.de> + * Copyright 2008 Michael Buesch <m@bues.ch> * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com> * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com> * Copyright 2008 Colin McCabe <colin@cozybit.com> @@ -77,6 +77,39 @@ */ /** + * DOC: Virtual interface / concurrency capabilities + * + * Some devices are able to operate with virtual MACs, they can have + * more than one virtual interface. The capability handling for this + * is a bit complex though, as there may be a number of restrictions + * on the types of concurrency that are supported. + * + * To start with, each device supports the interface types listed in + * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the + * types there no concurrency is implied. + * + * Once concurrency is desired, more attributes must be observed: + * To start with, since some interface types are purely managed in + * software, like the AP-VLAN type in mac80211 for example, there's + * an additional list of these, they can be added at any time and + * are only restricted by some semantic restrictions (e.g. AP-VLAN + * cannot be added without a corresponding AP interface). This list + * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute. + * + * Further, the list of supported combinations is exported. This is + * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically, + * it exports a list of "groups", and at any point in time the + * interfaces that are currently active must fall into any one of + * the advertised groups. Within each group, there are restrictions + * on the number of interfaces of different types that are supported + * and also the number of different channels, along with potentially + * some other restrictions. See &enum nl80211_if_combination_attrs. + * + * All together, these attributes define the concurrency of virtual + * interfaces that a given device supports. + */ + +/** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors @@ -128,6 +161,13 @@ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes. + * Following attributes are provided for drivers that generate full Beacon + * and Probe Response frames internally: %NL80211_ATTR_SSID, + * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, + * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, + * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, + * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP, + * %NL80211_ATTR_IE_ASSOC_RESP. * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, * parameters are like for %NL80211_CMD_SET_BEACON. * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it @@ -148,6 +188,10 @@ * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to * destination %NL80211_ATTR_MAC on the interface identified by * %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by + * %NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP. + * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by + * %NL80211_ATTR_MAC. * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the * the interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC @@ -172,10 +216,10 @@ * to the specified ISO/IEC 3166-1 alpha2 country code. The core will * store this as a valid request and then query userspace for it. * - * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the + * @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the * interface identified by %NL80211_ATTR_IFINDEX * - * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the + * @NL80211_CMD_SET_MESH_CONFIG: Set mesh networking properties for the * interface identified by %NL80211_ATTR_IFINDEX * * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The @@ -194,11 +238,36 @@ * * @NL80211_CMD_GET_SCAN: get scan results * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters + * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the + * probe requests at CCK rate or not. * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to * NL80211_CMD_GET_SCAN and on the "scan" multicast group) * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, * partial scan results may be available * + * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain + * intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL. + * Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS) + * are passed, they are used in the probe requests. For + * broadcast, a broadcast SSID must be passed (ie. an empty + * string). If no SSID is passed, no probe requests are sent and + * a passive scan is performed. %NL80211_ATTR_SCAN_FREQUENCIES, + * if passed, define which channels should be scanned; if not + * passed, all channels allowed for the current regulatory domain + * are used. Extra IEs can also be passed from the userspace by + * using the %NL80211_ATTR_IE attribute. + * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT + * if scheduled scan is not running. + * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan + * results available. + * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has + * stopped. The driver may issue this event at any time during a + * scheduled scan. One reason for stopping the scan is if the hardware + * does not support starting an association or a normal scan while running + * a scheduled scan. This event is also sent when the + * %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface + * is brought down while a scheduled scan was running. + * * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation * or noise level * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to @@ -365,6 +434,8 @@ * specified using %NL80211_ATTR_DURATION. When called, this operation * returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the * TX status event pertaining to the TX request. + * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the + * management frames at CCK rate or not in 2GHz band. * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this * command may be used with the corresponding cookie to cancel the wait * time if it is known that it is no longer necessary. @@ -406,11 +477,72 @@ * notification. This event is used to indicate that an unprotected * disassociation frame was dropped when MFP is in use. * + * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a + * beacon or probe response from a compatible mesh peer. This is only + * sent while no station information (sta_info) exists for the new peer + * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On + * reception of this notification, userspace may decide to create a new + * station (@NL80211_CMD_NEW_STATION). To stop this notification from + * reoccurring, the userspace authentication daemon may want to create the + * new station with the AUTHENTICATED flag unset and maybe change it later + * depending on the authentication result. + * + * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings. + * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings. + * Since wireless is more complex than wired ethernet, it supports + * various triggers. These triggers can be configured through this + * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For + * more background information, see + * http://wireless.kernel.org/en/users/Documentation/WoWLAN. + * + * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver + * the necessary information for supporting GTK rekey offload. This + * feature is typically used during WoWLAN. The configuration data + * is contained in %NL80211_ATTR_REKEY_DATA (which is nested and + * contains the data in sub-attributes). After rekeying happened, + * this command may also be sent by the driver as an MLME event to + * inform userspace of the new replay counter. + * + * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace + * of PMKSA caching dandidates. + * + * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup). + * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. + * + * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP + * (or GO) interface (i.e. hostapd) to ask for unexpected frames to + * implement sending deauth to stations that send unexpected class 3 + * frames. Also used as the event sent by the kernel when such a frame + * is received. + * For the event, the %NL80211_ATTR_MAC attribute carries the TA and + * other attributes like the interface index are present. + * If used as the command it must have an interface index and you can + * only unsubscribe from the event by closing the socket. Subscription + * is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events. + * + * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the + * associated station identified by %NL80211_ATTR_MAC sent a 4addr frame + * and wasn't already in a 4-addr VLAN. The event will be sent similarly + * to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener. + * + * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface + * by sending a null data frame to it and reporting when the frame is + * acknowleged. This is used to allow timing out inactive clients. Uses + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a + * direct reply with an %NL80211_ATTR_COOKIE that is later used to match + * up the event with the request. The event includes the same data and + * has %NL80211_ATTR_ACK set if the frame was ACKed. + * + * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from + * other BSSes when any interfaces are in AP mode. This helps implement + * OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME + * messages. Note that per PHY only one application may register. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ enum nl80211_commands { -/* don't change the order or add anything inbetween, this is ABI! */ +/* don't change the order or add anything between, this is ABI! */ NL80211_CMD_UNSPEC, NL80211_CMD_GET_WIPHY, /* can dump */ @@ -448,8 +580,8 @@ enum nl80211_commands { NL80211_CMD_SET_REG, NL80211_CMD_REQ_SET_REG, - NL80211_CMD_GET_MESH_PARAMS, - NL80211_CMD_SET_MESH_PARAMS, + NL80211_CMD_GET_MESH_CONFIG, + NL80211_CMD_SET_MESH_CONFIG, NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */, @@ -518,6 +650,31 @@ enum nl80211_commands { NL80211_CMD_UNPROT_DEAUTHENTICATE, NL80211_CMD_UNPROT_DISASSOCIATE, + NL80211_CMD_NEW_PEER_CANDIDATE, + + NL80211_CMD_GET_WOWLAN, + NL80211_CMD_SET_WOWLAN, + + NL80211_CMD_START_SCHED_SCAN, + NL80211_CMD_STOP_SCHED_SCAN, + NL80211_CMD_SCHED_SCAN_RESULTS, + NL80211_CMD_SCHED_SCAN_STOPPED, + + NL80211_CMD_SET_REKEY_OFFLOAD, + + NL80211_CMD_PMKSA_CANDIDATE, + + NL80211_CMD_TDLS_OPER, + NL80211_CMD_TDLS_MGMT, + + NL80211_CMD_UNEXPECTED_FRAME, + + NL80211_CMD_PROBE_CLIENT, + + NL80211_CMD_REGISTER_BEACONS, + + NL80211_CMD_UNEXPECTED_4ADDR_FRAME, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -538,6 +695,13 @@ enum nl80211_commands { #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE #define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT +#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS + +/* source-level API compatibility */ +#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG +#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG +#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE + /** * enum nl80211_attrs - nl80211 netlink attributes * @@ -608,7 +772,7 @@ enum nl80211_commands { * consisting of a nested array. * * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). - * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. + * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link. * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path * info given for %NL80211_CMD_GET_MPATH, nested attribute described at @@ -653,8 +817,14 @@ enum nl80211_commands { * * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with * a single scan request, a wiphy attribute. + * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can + * scan with a single scheduled scan request, a wiphy attribute. * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements * that can be added to a scan request + * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information + * elements that can be added to a scheduled scan request + * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be + * used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute. * * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive @@ -735,18 +905,20 @@ enum nl80211_commands { * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT * event (u16) * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating - * that protected APs should be used. + * that protected APs should be used. This is also used with NEW_BEACON to + * indicate that the BSS is to use protection. * - * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to - * indicate which unicast key ciphers will be used with the connection + * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON + * to indicate which unicast key ciphers will be used with the connection * (an array of u32). - * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate - * which group key cipher will be used with the connection (a u32). - * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate - * which WPA version(s) the AP we want to associate with is using + * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which group key cipher will be used with the connection (a + * u32). + * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which WPA version(s) the AP we want to associate with is using * (a u32 with flags from &enum nl80211_wpa_versions). - * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate - * which key management algorithm(s) to use (an array of u32). + * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which key management algorithm(s) to use (an array of u32). * * @NL80211_ATTR_REQ_IE: (Re)association request information elements as * sent out by the card, for ROAM and successful CONNECT events. @@ -852,7 +1024,13 @@ enum nl80211_commands { * This can be used to mask out antennas which are not attached or should * not be used for receiving. If an antenna is not selected in this bitmap * the hardware should not be configured to receive on this antenna. - * For a more detailed descripton see @NL80211_ATTR_WIPHY_ANTENNA_TX. + * For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX. + * + * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX: Bitmap of antennas which are available + * for configuration as TX antennas via the above parameters. + * + * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available + * for configuration as RX antennas via the above parameters. * * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS * @@ -868,11 +1046,135 @@ enum nl80211_commands { * attributes, specifying what a key should be set as default as. * See &enum nl80211_key_default_types. * + * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters. These cannot be + * changed once the mesh is active. + * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute + * containing attributes from &enum nl80211_meshconf_params. + * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver + * allows auth frames in a mesh to be passed to userspace for processing via + * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. + * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as + * defined in &enum nl80211_plink_state. Used when userspace is + * driving the peer link management state machine. + * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled. + * + * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy + * capabilities, the supported WoWLAN triggers + * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to + * indicate which WoW triggers should be enabled. This is also + * used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN + * triggers. + + * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan + * cycles, in msecs. + + * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more + * sets of attributes to match during scheduled scans. Only BSSs + * that match any of the sets will be reported. These are + * pass-thru filter rules. + * For a match to succeed, the BSS must match all attributes of a + * set. Since not every hardware supports matching all types of + * attributes, there is no guarantee that the reported BSSs are + * fully complying with the match sets and userspace needs to be + * able to ignore them by itself. + * Thus, the implementation is somewhat hardware-dependent, but + * this is only an optimization and the userspace application + * needs to handle all the non-filtered results anyway. + * If the match attributes don't make sense when combined with + * the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID + * is included in the probe request, but the match attributes + * will never let it go through), -EINVAL may be returned. + * If ommited, no filtering is done. + * + * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported + * interface combinations. In each nested item, it contains attributes + * defined in &enum nl80211_if_combination_attrs. + * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like + * %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that + * are managed in software: interfaces of these types aren't subject to + * any restrictions in their number or combinations. + * + * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information + * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data. + * + * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan, + * nested array attribute containing an entry for each band, with the entry + * being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but + * without the length restriction (at most %NL80211_MAX_SUPP_RATES). + * + * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon + * and Probe Response (when response to wildcard Probe Request); see + * &enum nl80211_hidden_ssid, represented as a u32 + * + * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame. + * This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to + * provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the + * driver (or firmware) replies to Probe Request frames. + * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association + * Response frames. This is used with %NL80211_CMD_NEW_BEACON and + * %NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into + * (Re)Association Response frames when the driver (or firmware) replies to + * (Re)Association Request frames. + * + * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration + * of the station, see &enum nl80211_sta_wme_attr. + * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working + * as AP. + * + * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of + * roaming to another AP in the same ESS if the signal lever is low. + * + * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching + * candidate information, see &enum nl80211_pmksa_candidate_attr. + * + * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not + * for management frames transmission. In order to avoid p2p probe/action + * frames are being transmitted at CCK rate in 2GHz band, the user space + * applications use this attribute. + * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and + * %NL80211_CMD_FRAME commands. + * + * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup + * request, link setup confirm, link teardown, etc.). Values are + * described in the TDLS (802.11z) specification. + * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a + * TDLS conversation between two devices. + * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see + * &enum nl80211_tdls_operation, represented as a u8. + * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate + * as a TDLS peer sta. + * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown + * procedures should be performed by sending TDLS packets via + * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be + * used for asking the driver to perform a TDLS operation. + * + * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices + * that have AP support to indicate that they have the AP SME integrated + * with support for the features listed in this attribute, see + * &enum nl80211_ap_sme_features. + * + * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells + * the driver to not wait for an acknowledgement. Note that due to this, + * it will also not give a status callback nor return a cookie. This is + * mostly useful for probe responses to save airtime. + * + * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from + * &enum nl80211_feature_flags and is advertised in wiphy information. + * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe + * + * requests while operating in AP-mode. + * This attribute holds a bitmap of the supported protocols for + * offloading (see &enum nl80211_probe_resp_offload_support_attr). + * + * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire + * probe-response frame. The DA field in the 802.11 header is zero-ed out, + * to be filled by the FW. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ enum nl80211_attrs { -/* don't change the order or add anything inbetween, this is ABI! */ +/* don't change the order or add anything between, this is ABI! */ NL80211_ATTR_UNSPEC, NL80211_ATTR_WIPHY, @@ -922,7 +1224,7 @@ enum nl80211_attrs { NL80211_ATTR_REG_ALPHA2, NL80211_ATTR_REG_RULES, - NL80211_ATTR_MESH_PARAMS, + NL80211_ATTR_MESH_CONFIG, NL80211_ATTR_BSS_BASIC_RATES, @@ -1050,6 +1352,62 @@ enum nl80211_attrs { NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, + NL80211_ATTR_MESH_SETUP, + + NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, + NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, + + NL80211_ATTR_SUPPORT_MESH_AUTH, + NL80211_ATTR_STA_PLINK_STATE, + + NL80211_ATTR_WOWLAN_TRIGGERS, + NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, + + NL80211_ATTR_SCHED_SCAN_INTERVAL, + + NL80211_ATTR_INTERFACE_COMBINATIONS, + NL80211_ATTR_SOFTWARE_IFTYPES, + + NL80211_ATTR_REKEY_DATA, + + NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, + NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, + + NL80211_ATTR_SCAN_SUPP_RATES, + + NL80211_ATTR_HIDDEN_SSID, + + NL80211_ATTR_IE_PROBE_RESP, + NL80211_ATTR_IE_ASSOC_RESP, + + NL80211_ATTR_STA_WME, + NL80211_ATTR_SUPPORT_AP_UAPSD, + + NL80211_ATTR_ROAM_SUPPORT, + + NL80211_ATTR_SCHED_SCAN_MATCH, + NL80211_ATTR_MAX_MATCH_SETS, + + NL80211_ATTR_PMKSA_CANDIDATE, + + NL80211_ATTR_TX_NO_CCK_RATE, + + NL80211_ATTR_TDLS_ACTION, + NL80211_ATTR_TDLS_DIALOG_TOKEN, + NL80211_ATTR_TDLS_OPERATION, + NL80211_ATTR_TDLS_SUPPORT, + NL80211_ATTR_TDLS_EXTERNAL_SETUP, + + NL80211_ATTR_DEVICE_AP_SME, + + NL80211_ATTR_DONT_WAIT_FOR_ACK, + + NL80211_ATTR_FEATURE_FLAGS, + + NL80211_ATTR_PROBE_RESP_OFFLOAD, + + NL80211_ATTR_PROBE_RESP, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1058,6 +1416,7 @@ enum nl80211_attrs { /* source-level API compatibility */ #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION +#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG /* * Allow user space programs to use #ifdef on new attributes by defining them @@ -1083,6 +1442,7 @@ enum nl80211_attrs { #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES #define NL80211_ATTR_KEY NL80211_ATTR_KEY #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS +#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_REG_RULES 32 @@ -1101,7 +1461,9 @@ enum nl80211_attrs { * @NL80211_IFTYPE_ADHOC: independent BSS member * @NL80211_IFTYPE_STATION: managed BSS member * @NL80211_IFTYPE_AP: access point - * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points + * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces + * are a bit special in that they must always be tied to a pre-existing + * AP type interface. * @NL80211_IFTYPE_WDS: wireless distribution interface * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames * @NL80211_IFTYPE_MESH_POINT: mesh point @@ -1143,6 +1505,8 @@ enum nl80211_iftype { * with short barker preamble * @NL80211_STA_FLAG_WME: station is WME/QoS capable * @NL80211_STA_FLAG_MFP: station uses management frame protection + * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated + * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer * @NL80211_STA_FLAG_MAX: highest station flag number currently defined * @__NL80211_STA_FLAG_AFTER_LAST: internal use */ @@ -1152,6 +1516,8 @@ enum nl80211_sta_flags { NL80211_STA_FLAG_SHORT_PREAMBLE, NL80211_STA_FLAG_WME, NL80211_STA_FLAG_MFP, + NL80211_STA_FLAG_AUTHENTICATED, + NL80211_STA_FLAG_TDLS_PEER, /* keep last */ __NL80211_STA_FLAG_AFTER_LAST, @@ -1197,6 +1563,36 @@ enum nl80211_rate_info { }; /** + * enum nl80211_sta_bss_param - BSS information collected by STA + * + * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM + * when getting information about the bitrate of a station. + * + * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved + * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag) + * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE: whether short preamble is enabled + * (flag) + * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME: whether short slot time is enabled + * (flag) + * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8) + * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16) + * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined + * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use + */ +enum nl80211_sta_bss_param { + __NL80211_STA_BSS_PARAM_INVALID, + NL80211_STA_BSS_PARAM_CTS_PROT, + NL80211_STA_BSS_PARAM_SHORT_PREAMBLE, + NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME, + NL80211_STA_BSS_PARAM_DTIM_PERIOD, + NL80211_STA_BSS_PARAM_BEACON_INTERVAL, + + /* keep last */ + __NL80211_STA_BSS_PARAM_AFTER_LAST, + NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1 +}; + +/** * enum nl80211_sta_info - station information * * These attribute types are used with %NL80211_ATTR_STA_INFO @@ -1206,17 +1602,27 @@ enum nl80211_rate_info { * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) - * @__NL80211_STA_INFO_AFTER_LAST: internal - * @NL80211_STA_INFO_MAX: highest possible station info attribute * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute - * containing info as possible, see &enum nl80211_sta_info_txrate. + * containing info as possible, see &enum nl80211_rate_info * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this * station) * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station) * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station) * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm) + * @NL80211_STA_INFO_LLID: the station's mesh LLID + * @NL80211_STA_INFO_PLID: the station's mesh PLID + * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station + * (see %enum nl80211_plink_state) + * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested + * attribute, like NL80211_STA_INFO_TX_BITRATE. + * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute + * containing info as possible, see &enum nl80211_sta_bss_param + * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected + * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update. + * @__NL80211_STA_INFO_AFTER_LAST: internal + * @NL80211_STA_INFO_MAX: highest possible station info attribute */ enum nl80211_sta_info { __NL80211_STA_INFO_INVALID, @@ -1233,6 +1639,10 @@ enum nl80211_sta_info { NL80211_STA_INFO_TX_RETRIES, NL80211_STA_INFO_TX_FAILED, NL80211_STA_INFO_SIGNAL_AVG, + NL80211_STA_INFO_RX_BITRATE, + NL80211_STA_INFO_BSS_PARAM, + NL80211_STA_INFO_CONNECTED_TIME, + NL80211_STA_INFO_STA_FLAGS, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, @@ -1388,7 +1798,7 @@ enum nl80211_bitrate_attr { * 802.11 country information element with regulatory information it * thinks we should consider. cfg80211 only processes the country * code from the IE, and relies on the regulatory domain information - * structure pased by userspace (CRDA) from our wireless-regdb. + * structure passed by userspace (CRDA) from our wireless-regdb. * If a channel is enabled but the country code indicates it should * be disabled we disable the channel and re-enable it upon disassociation. */ @@ -1462,6 +1872,26 @@ enum nl80211_reg_rule_attr { }; /** + * enum nl80211_sched_scan_match_attr - scheduled scan match attributes + * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching, + * only report BSS with matching SSID. + * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter + * attribute number currently defined + * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use + */ +enum nl80211_sched_scan_match_attr { + __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID, + + NL80211_ATTR_SCHED_SCAN_MATCH_SSID, + + /* keep last */ + __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, + NL80211_SCHED_SCAN_MATCH_ATTR_MAX = + __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1 +}; + +/** * enum nl80211_reg_rule_flags - regulatory rule flags * * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed @@ -1559,14 +1989,15 @@ enum nl80211_mntr_flags { /** * enum nl80211_meshconf_params - mesh configuration parameters * - * Mesh configuration parameters + * Mesh configuration parameters. These can be changed while the mesh is + * active. * * @__NL80211_MESHCONF_INVALID: internal use * * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in * millisecond units, used by the Peer Link Open message * - * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in + * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in * millisecond units, used by the peer link management to close a peer link * * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in @@ -1582,9 +2013,6 @@ enum nl80211_mntr_flags { * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh * point. * - * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a - * source mesh point for path selection elements. - * * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically * open peer links when we detect compatible mesh peers. * @@ -1609,7 +2037,17 @@ enum nl80211_mntr_flags { * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) * that it takes for an HWMP information element to propagate across the mesh * - * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not + * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not + * + * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a + * source mesh point for path selection elements. + * + * @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between + * root announcements are transmitted. + * + * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has + * access to a broader network beyond the MBSS. This is done via Root + * Announcement frames. * * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute * @@ -1632,6 +2070,8 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, NL80211_MESHCONF_HWMP_ROOTMODE, NL80211_MESHCONF_ELEMENT_TTL, + NL80211_MESHCONF_HWMP_RANN_INTERVAL, + NL80211_MESHCONF_GATE_ANNOUNCEMENTS, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, @@ -1639,6 +2079,54 @@ enum nl80211_meshconf_params { }; /** + * enum nl80211_mesh_setup_params - mesh setup parameters + * + * Mesh setup parameters. These are used to start/join a mesh and cannot be + * changed while the mesh is active. + * + * @__NL80211_MESH_SETUP_INVALID: Internal use + * + * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a + * vendor specific path selection algorithm or disable it to use the default + * HWMP. + * + * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a + * vendor specific path metric or disable it to use the default Airtime + * metric. + * + * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a + * robust security network ie, or a vendor specific information element that + * vendors will use to identify the path selection methods and metrics in use. + * + * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication + * daemon will be authenticating mesh candidates. + * + * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication + * daemon will be securing peer link frames. AMPE is a secured version of Mesh + * Peering Management (MPM) and is implemented with the assistance of a + * userspace daemon. When this flag is set, the kernel will send peer + * management frames to a userspace daemon that will implement AMPE + * functionality (security capabilities selection, key confirmation, and key + * management). When the flag is unset (default), the kernel can autonomously + * complete (unsecured) mesh peering without the need of a userspace daemon. + * + * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number + * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use + */ +enum nl80211_mesh_setup_params { + __NL80211_MESH_SETUP_INVALID, + NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL, + NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC, + NL80211_MESH_SETUP_IE, + NL80211_MESH_SETUP_USERSPACE_AUTH, + NL80211_MESH_SETUP_USERSPACE_AMPE, + + /* keep last */ + __NL80211_MESH_SETUP_ATTR_AFTER_LAST, + NL80211_MESH_SETUP_ATTR_MAX = __NL80211_MESH_SETUP_ATTR_AFTER_LAST - 1 +}; + +/** * enum nl80211_txq_attr - TX queue parameter attributes * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*) @@ -1936,4 +2424,341 @@ enum nl80211_tx_power_setting { NL80211_TX_POWER_FIXED, }; +/** + * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute + * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute + * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has + * a zero bit are ignored + * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have + * a bit for each byte in the pattern. The lowest-order bit corresponds + * to the first byte of the pattern, but the bytes of the pattern are + * in a little-endian-like format, i.e. the 9th byte of the pattern + * corresponds to the lowest-order bit in the second byte of the mask. + * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where + * xx indicates "don't care") would be represented by a pattern of + * twelve zero bytes, and a mask of "0xed,0x07". + * Note that the pattern matching is done as though frames were not + * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked + * first (including SNAP header unpacking) and then matched. + * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes + * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number + */ +enum nl80211_wowlan_packet_pattern_attr { + __NL80211_WOWLAN_PKTPAT_INVALID, + NL80211_WOWLAN_PKTPAT_MASK, + NL80211_WOWLAN_PKTPAT_PATTERN, + + NUM_NL80211_WOWLAN_PKTPAT, + MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, +}; + +/** + * struct nl80211_wowlan_pattern_support - pattern support information + * @max_patterns: maximum number of patterns supported + * @min_pattern_len: minimum length of each pattern + * @max_pattern_len: maximum length of each pattern + * + * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when + * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the + * capability information given by the kernel to userspace. + */ +struct nl80211_wowlan_pattern_support { + __u32 max_patterns; + __u32 min_pattern_len; + __u32 max_pattern_len; +} __attribute__((packed)); + +/** + * enum nl80211_wowlan_triggers - WoWLAN trigger definitions + * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes + * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put + * the chip into a special state -- works best with chips that have + * support for low-power operation already (flag) + * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect + * is detected is implementation-specific (flag) + * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed + * by 16 repetitions of MAC addr, anywhere in payload) (flag) + * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns + * which are passed in an array of nested attributes, each nested attribute + * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern. + * Each pattern defines a wakeup packet. The matching is done on the MSDU, + * i.e. as though the packet was an 802.3 packet, so the pattern matching + * is done after the packet is converted to the MSDU. + * + * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute + * carrying a &struct nl80211_wowlan_pattern_support. + * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be + * used when setting, used only to indicate that GTK rekeying is supported + * by the device (flag) + * @NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE: wake up on GTK rekey failure (if + * done by the device) (flag) + * @NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST: wake up on EAP Identity Request + * packet (flag) + * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag) + * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released + * (on devices that have rfkill in the device) (flag) + * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers + * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number + */ +enum nl80211_wowlan_triggers { + __NL80211_WOWLAN_TRIG_INVALID, + NL80211_WOWLAN_TRIG_ANY, + NL80211_WOWLAN_TRIG_DISCONNECT, + NL80211_WOWLAN_TRIG_MAGIC_PKT, + NL80211_WOWLAN_TRIG_PKT_PATTERN, + NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED, + NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE, + NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, + NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, + NL80211_WOWLAN_TRIG_RFKILL_RELEASE, + + /* keep last */ + NUM_NL80211_WOWLAN_TRIG, + MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1 +}; + +/** + * enum nl80211_iface_limit_attrs - limit attributes + * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) + * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that + * can be chosen from this set of interface types (u32) + * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a + * flag attribute for each interface type in this set + * @NUM_NL80211_IFACE_LIMIT: number of attributes + * @MAX_NL80211_IFACE_LIMIT: highest attribute number + */ +enum nl80211_iface_limit_attrs { + NL80211_IFACE_LIMIT_UNSPEC, + NL80211_IFACE_LIMIT_MAX, + NL80211_IFACE_LIMIT_TYPES, + + /* keep last */ + NUM_NL80211_IFACE_LIMIT, + MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1 +}; + +/** + * enum nl80211_if_combination_attrs -- interface combination attributes + * + * @NL80211_IFACE_COMB_UNSPEC: (reserved) + * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits + * for given interface types, see &enum nl80211_iface_limit_attrs. + * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of + * interfaces that can be created in this group. This number doesn't + * apply to interfaces purely managed in software, which are listed + * in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE. + * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that + * beacon intervals within this group must be all the same even for + * infrastructure and AP/GO combinations, i.e. the GO(s) must adopt + * the infrastructure network's beacon interval. + * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many + * different channels may be used within this group. + * @NUM_NL80211_IFACE_COMB: number of attributes + * @MAX_NL80211_IFACE_COMB: highest attribute number + * + * Examples: + * limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2 + * => allows an AP and a STA that must match BIs + * + * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8 + * => allows 8 of AP/GO + * + * numbers = [ #{STA} <= 2 ], channels = 2, max = 2 + * => allows two STAs on different channels + * + * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4 + * => allows a STA plus three P2P interfaces + * + * The list of these four possiblities could completely be contained + * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate + * that any of these groups must match. + * + * "Combinations" of just a single interface will not be listed here, + * a single interface of any valid interface type is assumed to always + * be possible by itself. This means that implicitly, for each valid + * interface type, the following group always exists: + * numbers = [ #{<type>} <= 1 ], channels = 1, max = 1 + */ +enum nl80211_if_combination_attrs { + NL80211_IFACE_COMB_UNSPEC, + NL80211_IFACE_COMB_LIMITS, + NL80211_IFACE_COMB_MAXNUM, + NL80211_IFACE_COMB_STA_AP_BI_MATCH, + NL80211_IFACE_COMB_NUM_CHANNELS, + + /* keep last */ + NUM_NL80211_IFACE_COMB, + MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1 +}; + + +/** + * enum nl80211_plink_state - state of a mesh peer link finite state machine + * + * @NL80211_PLINK_LISTEN: initial state, considered the implicit + * state of non existant mesh peer links + * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to + * this mesh peer + * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received + * from this mesh peer + * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been + * received from this mesh peer + * @NL80211_PLINK_ESTAB: mesh peer link is established + * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled + * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh + * plink are discarded + * @NUM_NL80211_PLINK_STATES: number of peer link states + * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states + */ +enum nl80211_plink_state { + NL80211_PLINK_LISTEN, + NL80211_PLINK_OPN_SNT, + NL80211_PLINK_OPN_RCVD, + NL80211_PLINK_CNF_RCVD, + NL80211_PLINK_ESTAB, + NL80211_PLINK_HOLDING, + NL80211_PLINK_BLOCKED, + + /* keep last */ + NUM_NL80211_PLINK_STATES, + MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1 +}; + +#define NL80211_KCK_LEN 16 +#define NL80211_KEK_LEN 16 +#define NL80211_REPLAY_CTR_LEN 8 + +/** + * enum nl80211_rekey_data - attributes for GTK rekey offload + * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes + * @NL80211_REKEY_DATA_KEK: key encryption key (binary) + * @NL80211_REKEY_DATA_KCK: key confirmation key (binary) + * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary) + * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal) + * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal) + */ +enum nl80211_rekey_data { + __NL80211_REKEY_DATA_INVALID, + NL80211_REKEY_DATA_KEK, + NL80211_REKEY_DATA_KCK, + NL80211_REKEY_DATA_REPLAY_CTR, + + /* keep last */ + NUM_NL80211_REKEY_DATA, + MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1 +}; + +/** + * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID + * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in + * Beacon frames) + * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element + * in Beacon frames + * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID + * element in Beacon frames but zero out each byte in the SSID + */ +enum nl80211_hidden_ssid { + NL80211_HIDDEN_SSID_NOT_IN_USE, + NL80211_HIDDEN_SSID_ZERO_LEN, + NL80211_HIDDEN_SSID_ZERO_CONTENTS +}; + +/** + * enum nl80211_sta_wme_attr - station WME attributes + * @__NL80211_STA_WME_INVALID: invalid number for nested attribute + * @NL80211_STA_WME_UAPSD_QUEUES: bitmap of uapsd queues. the format + * is the same as the AC bitmap in the QoS info field. + * @NL80211_STA_WME_MAX_SP: max service period. the format is the same + * as the MAX_SP field in the QoS info field (but already shifted down). + * @__NL80211_STA_WME_AFTER_LAST: internal + * @NL80211_STA_WME_MAX: highest station WME attribute + */ +enum nl80211_sta_wme_attr { + __NL80211_STA_WME_INVALID, + NL80211_STA_WME_UAPSD_QUEUES, + NL80211_STA_WME_MAX_SP, + + /* keep last */ + __NL80211_STA_WME_AFTER_LAST, + NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1 +}; + +/** + * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates + * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes + * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher + * priority) + * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets) + * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag) + * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes + * (internal) + * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute + * (internal) + */ +enum nl80211_pmksa_candidate_attr { + __NL80211_PMKSA_CANDIDATE_INVALID, + NL80211_PMKSA_CANDIDATE_INDEX, + NL80211_PMKSA_CANDIDATE_BSSID, + NL80211_PMKSA_CANDIDATE_PREAUTH, + + /* keep last */ + NUM_NL80211_PMKSA_CANDIDATE, + MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1 +}; + +/** + * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION + * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request + * @NL80211_TDLS_SETUP: Setup TDLS link + * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established + * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link + * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link + */ +enum nl80211_tdls_operation { + NL80211_TDLS_DISCOVERY_REQ, + NL80211_TDLS_SETUP, + NL80211_TDLS_TEARDOWN, + NL80211_TDLS_ENABLE_LINK, + NL80211_TDLS_DISABLE_LINK, +}; + +/* + * enum nl80211_ap_sme_features - device-integrated AP features + * Reserved for future use, no bits are defined in + * NL80211_ATTR_DEVICE_AP_SME yet. +enum nl80211_ap_sme_features { +}; + */ + +/** + * enum nl80211_feature_flags - device/driver features + * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back + * TX status to the socket error queue when requested with the + * socket option. + */ +enum nl80211_feature_flags { + NL80211_FEATURE_SK_TX_STATUS = 1 << 0, +}; + +/** + * enum nl80211_probe_resp_offload_support_attr - optional supported + * protocols for probe-response offloading by the driver/FW. + * To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute. + * Each enum value represents a bit in the bitmap of supported + * protocols. Typically a subset of probe-requests belonging to a + * supported protocol will be excluded from offload and uploaded + * to the host. + * + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1 + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2 + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u + */ +enum nl80211_probe_resp_offload_support_attr { + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS = 1<<0, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 = 1<<1, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P = 1<<2, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/src/drivers/wireless_copy.h b/src/drivers/wireless_copy.h deleted file mode 100644 index 201719b..0000000 --- a/src/drivers/wireless_copy.h +++ /dev/null @@ -1,1185 +0,0 @@ -/* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 22. - * I have just removed kernel related headers and added some typedefs etc. to - * make this easier to include into user space programs. - * Jouni Malinen, 2005-03-12. - */ - - -/* - * This file define a set of standard wireless extensions - * - * Version : 22 16.3.07 - * - * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> - * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. - */ - -#ifndef _LINUX_WIRELESS_H -#define _LINUX_WIRELESS_H - -/************************** DOCUMENTATION **************************/ -/* - * Initial APIs (1996 -> onward) : - * ----------------------------- - * Basically, the wireless extensions are for now a set of standard ioctl - * call + /proc/net/wireless - * - * The entry /proc/net/wireless give statistics and information on the - * driver. - * This is better than having each driver having its entry because - * its centralised and we may remove the driver module safely. - * - * Ioctl are used to configure the driver and issue commands. This is - * better than command line options of insmod because we may want to - * change dynamically (while the driver is running) some parameters. - * - * The ioctl mechanimsm are copied from standard devices ioctl. - * We have the list of command plus a structure descibing the - * data exchanged... - * Note that to add these ioctl, I was obliged to modify : - * # net/core/dev.c (two place + add include) - * # net/ipv4/af_inet.c (one place + add include) - * - * /proc/net/wireless is a copy of /proc/net/dev. - * We have a structure for data passed from the driver to /proc/net/wireless - * Too add this, I've modified : - * # net/core/dev.c (two other places) - * # include/linux/netdevice.h (one place) - * # include/linux/proc_fs.h (one place) - * - * New driver API (2002 -> onward) : - * ------------------------------- - * This file is only concerned with the user space API and common definitions. - * The new driver API is defined and documented in : - * # include/net/iw_handler.h - * - * Note as well that /proc/net/wireless implementation has now moved in : - * # net/core/wireless.c - * - * Wireless Events (2002 -> onward) : - * -------------------------------- - * Events are defined at the end of this file, and implemented in : - * # net/core/wireless.c - * - * Other comments : - * -------------- - * Do not add here things that are redundant with other mechanisms - * (drivers init, ifconfig, /proc/net/dev, ...) and with are not - * wireless specific. - * - * These wireless extensions are not magic : each driver has to provide - * support for them... - * - * IMPORTANT NOTE : As everything in the kernel, this is very much a - * work in progress. Contact me if you have ideas of improvements... - */ - -/***************************** INCLUDES *****************************/ - - /* jkm - replaced linux headers with C library headers, added typedefs */ -#if 0 -#include <linux/types.h> /* for __u* and __s* typedefs */ -#include <linux/socket.h> /* for "struct sockaddr" et al */ -#include <linux/if.h> /* for IFNAMSIZ and co... */ -#else -#include <sys/types.h> -#include <net/if.h> -#ifndef ANDROID -typedef __uint32_t __u32; -typedef __int32_t __s32; -typedef __uint16_t __u16; -typedef __int16_t __s16; -typedef __uint8_t __u8; -#endif /* ANDROID */ -#ifndef __user -#define __user -#endif /* __user */ -#endif - -/***************************** VERSION *****************************/ -/* - * This constant is used to know the availability of the wireless - * extensions and to know which version of wireless extensions it is - * (there is some stuff that will be added in the future...) - * I just plan to increment with each new version. - */ -#define WIRELESS_EXT 22 - -/* - * Changes : - * - * V2 to V3 - * -------- - * Alan Cox start some incompatibles changes. I've integrated a bit more. - * - Encryption renamed to Encode to avoid US regulation problems - * - Frequency changed from float to struct to avoid problems on old 386 - * - * V3 to V4 - * -------- - * - Add sensitivity - * - * V4 to V5 - * -------- - * - Missing encoding definitions in range - * - Access points stuff - * - * V5 to V6 - * -------- - * - 802.11 support (ESSID ioctls) - * - * V6 to V7 - * -------- - * - define IW_ESSID_MAX_SIZE and IW_MAX_AP - * - * V7 to V8 - * -------- - * - Changed my e-mail address - * - More 802.11 support (nickname, rate, rts, frag) - * - List index in frequencies - * - * V8 to V9 - * -------- - * - Support for 'mode of operation' (ad-hoc, managed...) - * - Support for unicast and multicast power saving - * - Change encoding to support larger tokens (>64 bits) - * - Updated iw_params (disable, flags) and use it for NWID - * - Extracted iw_point from iwreq for clarity - * - * V9 to V10 - * --------- - * - Add PM capability to range structure - * - Add PM modifier : MAX/MIN/RELATIVE - * - Add encoding option : IW_ENCODE_NOKEY - * - Add TxPower ioctls (work like TxRate) - * - * V10 to V11 - * ---------- - * - Add WE version in range (help backward/forward compatibility) - * - Add retry ioctls (work like PM) - * - * V11 to V12 - * ---------- - * - Add SIOCSIWSTATS to get /proc/net/wireless programatically - * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space - * - Add new statistics (frag, retry, beacon) - * - Add average quality (for user space calibration) - * - * V12 to V13 - * ---------- - * - Document creation of new driver API. - * - Extract union iwreq_data from struct iwreq (for new driver API). - * - Rename SIOCSIWNAME as SIOCSIWCOMMIT - * - * V13 to V14 - * ---------- - * - Wireless Events support : define struct iw_event - * - Define additional specific event numbers - * - Add "addr" and "param" fields in union iwreq_data - * - AP scanning stuff (SIOCSIWSCAN and friends) - * - * V14 to V15 - * ---------- - * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg - * - Make struct iw_freq signed (both m & e), add explicit padding - * - Add IWEVCUSTOM for driver specific event/scanning token - * - Add IW_MAX_GET_SPY for driver returning a lot of addresses - * - Add IW_TXPOW_RANGE for range of Tx Powers - * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points - * - Add IW_MODE_MONITOR for passive monitor - * - * V15 to V16 - * ---------- - * - Increase the number of bitrates in iw_range to 32 (for 802.11g) - * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a) - * - Reshuffle struct iw_range for increases, add filler - * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses - * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support - * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy" - * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index - * - * V16 to V17 - * ---------- - * - Add flags to frequency -> auto/fixed - * - Document (struct iw_quality *)->updated, add new flags (INVALID) - * - Wireless Event capability in struct iw_range - * - Add support for relative TxPower (yick !) - * - * V17 to V18 (From Jouni Malinen <j@w1.fi>) - * ---------- - * - Add support for WPA/WPA2 - * - Add extended encoding configuration (SIOCSIWENCODEEXT and - * SIOCGIWENCODEEXT) - * - Add SIOCSIWGENIE/SIOCGIWGENIE - * - Add SIOCSIWMLME - * - Add SIOCSIWPMKSA - * - Add struct iw_range bit field for supported encoding capabilities - * - Add optional scan request parameters for SIOCSIWSCAN - * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA - * related parameters (extensible up to 4096 parameter values) - * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE, - * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND - * - * V18 to V19 - * ---------- - * - Remove (struct iw_point *)->pointer from events and streams - * - Remove header includes to help user space - * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64 - * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros - * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM - * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros - * - * V19 to V20 - * ---------- - * - RtNetlink requests support (SET/GET) - * - * V20 to V21 - * ---------- - * - Remove (struct net_device *)->get_wireless_stats() - * - Change length in ESSID and NICK to strlen() instead of strlen()+1 - * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers - * - Power/Retry relative values no longer * 100000 - * - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI - * - * V21 to V22 - * ---------- - * - Prevent leaking of kernel space in stream on 64 bits. - */ - -/**************************** CONSTANTS ****************************/ - -/* -------------------------- IOCTL LIST -------------------------- */ - -/* Wireless Identification */ -#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ -#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ -/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. - * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... - * Don't put the name of your driver there, it's useless. */ - -/* Basic operations */ -#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ -#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ -#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ -#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ -#define SIOCSIWMODE 0x8B06 /* set operation mode */ -#define SIOCGIWMODE 0x8B07 /* get operation mode */ -#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ -#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ - -/* Informative stuff */ -#define SIOCSIWRANGE 0x8B0A /* Unused */ -#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ -#define SIOCSIWPRIV 0x8B0C /* Unused */ -#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ -#define SIOCSIWSTATS 0x8B0E /* Unused */ -#define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ -/* SIOCGIWSTATS is strictly used between user space and the kernel, and - * is never passed to the driver (i.e. the driver will never see it). */ - -/* Spy support (statistics per MAC address - used for Mobile IP support) */ -#define SIOCSIWSPY 0x8B10 /* set spy addresses */ -#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ -#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */ -#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */ - -/* Access Point manipulation */ -#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ -#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ -#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ -#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ -#define SIOCGIWSCAN 0x8B19 /* get scanning results */ - -/* 802.11 specific support */ -#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ -#define SIOCGIWESSID 0x8B1B /* get ESSID */ -#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */ -#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ -/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit - * within the 'iwreq' structure, so we need to use the 'data' member to - * point to a string in user space, like it is done for RANGE... */ - -/* Other parameters useful in 802.11 and some other devices */ -#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ -#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ -#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ -#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ -#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ -#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ -#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ -#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ -#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ -#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ - -/* Encoding stuff (scrambling, hardware security, WEP...) */ -#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ -#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */ -/* Power saving stuff (power management, unicast and multicast) */ -#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */ -#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */ - -/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM). - * This ioctl uses struct iw_point and data buffer that includes IE id and len - * fields. More than one IE may be included in the request. Setting the generic - * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers - * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers - * are required to report the used IE as a wireless event, e.g., when - * associating with an AP. */ -#define SIOCSIWGENIE 0x8B30 /* set generic IE */ -#define SIOCGIWGENIE 0x8B31 /* get generic IE */ - -/* WPA : IEEE 802.11 MLME requests */ -#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses - * struct iw_mlme */ -/* WPA : Authentication mode parameters */ -#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ -#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ - -/* WPA : Extended version of encoding configuration */ -#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ -#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ - -/* WPA2 : PMKSA cache management */ -#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ - -/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */ - -/* These 32 ioctl are wireless device private, for 16 commands. - * Each driver is free to use them for whatever purpose it chooses, - * however the driver *must* export the description of those ioctls - * with SIOCGIWPRIV and *must* use arguments as defined below. - * If you don't follow those rules, DaveM is going to hate you (reason : - * it make mixed 32/64bit operation impossible). - */ -#define SIOCIWFIRSTPRIV 0x8BE0 -#define SIOCIWLASTPRIV 0x8BFF -/* Previously, we were using SIOCDEVPRIVATE, but we now have our - * separate range because of collisions with other tools such as - * 'mii-tool'. - * We now have 32 commands, so a bit more space ;-). - * Also, all 'even' commands are only usable by root and don't return the - * content of ifr/iwr to user (but you are not obliged to use the set/get - * convention, just use every other two command). More details in iwpriv.c. - * And I repeat : you are not forced to use them with iwpriv, but you - * must be compliant with it. - */ - -/* ------------------------- IOCTL STUFF ------------------------- */ - -/* The first and the last (range) */ -#define SIOCIWFIRST 0x8B00 -#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */ -#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) -#define IW_HANDLER(id, func) \ - [IW_IOCTL_IDX(id)] = func - -/* Odd : get (world access), even : set (root access) */ -#define IW_IS_SET(cmd) (!((cmd) & 0x1)) -#define IW_IS_GET(cmd) ((cmd) & 0x1) - -/* ----------------------- WIRELESS EVENTS ----------------------- */ -/* Those are *NOT* ioctls, do not issue request on them !!! */ -/* Most events use the same identifier as ioctl requests */ - -#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ -#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ -#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ -#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ -#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ -#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) - * (scan results); This includes id and - * length fields. One IWEVGENIE may - * contain more than one IE. Scan - * results may contain one or more - * IWEVGENIE events. */ -#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure - * (struct iw_michaelmicfailure) - */ -#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. - * The data includes id and length - * fields and may contain more than one - * IE. This event is required in - * Managed mode if the driver - * generates its own WPA/RSN IE. This - * should be sent just before - * IWEVREGISTERED event for the - * association. */ -#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association - * Response. The data includes id and - * length fields and may contain more - * than one IE. This may be sent - * between IWEVASSOCREQIE and - * IWEVREGISTERED events for the - * association. */ -#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN - * pre-authentication - * (struct iw_pmkid_cand) */ - -#define IWEVFIRST 0x8C00 -#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) - -/* ------------------------- PRIVATE INFO ------------------------- */ -/* - * The following is used with SIOCGIWPRIV. It allow a driver to define - * the interface (name, type of data) for its private ioctl. - * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV - */ - -#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */ -#define IW_PRIV_TYPE_NONE 0x0000 -#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ -#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ -#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ -#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ -#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ - -#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */ - -#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ - -/* - * Note : if the number of args is fixed and the size < 16 octets, - * instead of passing a pointer we will put args in the iwreq struct... - */ - -/* ----------------------- OTHER CONSTANTS ----------------------- */ - -/* Maximum frequencies in the range struct */ -#define IW_MAX_FREQUENCIES 32 -/* Note : if you have something like 80 frequencies, - * don't increase this constant and don't fill the frequency list. - * The user will be able to set by channel anyway... */ - -/* Maximum bit rates in the range struct */ -#define IW_MAX_BITRATES 32 - -/* Maximum tx powers in the range struct */ -#define IW_MAX_TXPOWER 8 -/* Note : if you more than 8 TXPowers, just set the max and min or - * a few of them in the struct iw_range. */ - -/* Maximum of address that you may set with SPY */ -#define IW_MAX_SPY 8 - -/* Maximum of address that you may get in the - list of access points in range */ -#define IW_MAX_AP 64 - -/* Maximum size of the ESSID and NICKN strings */ -#define IW_ESSID_MAX_SIZE 32 - -/* Modes of operation */ -#define IW_MODE_AUTO 0 /* Let the driver decides */ -#define IW_MODE_ADHOC 1 /* Single cell network */ -#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ -#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ -#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ -#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ -#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ -#define IW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */ - -/* Statistics flags (bitmask in updated) */ -#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ -#define IW_QUAL_LEVEL_UPDATED 0x02 -#define IW_QUAL_NOISE_UPDATED 0x04 -#define IW_QUAL_ALL_UPDATED 0x07 -#define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */ -#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ -#define IW_QUAL_LEVEL_INVALID 0x20 -#define IW_QUAL_NOISE_INVALID 0x40 -#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */ -#define IW_QUAL_ALL_INVALID 0x70 - -/* Frequency flags */ -#define IW_FREQ_AUTO 0x00 /* Let the driver decides */ -#define IW_FREQ_FIXED 0x01 /* Force a specific value */ - -/* Maximum number of size of encoding token available - * they are listed in the range structure */ -#define IW_MAX_ENCODING_SIZES 8 - -/* Maximum size of the encoding token in bytes */ -#define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */ - -/* Flags for encoding (along with the token) */ -#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ -#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ -#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ -#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ -#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ -#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ -#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ -#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ -#define IW_ENCODE_TEMP 0x0400 /* Temporary key */ - -/* Power management flags available (along with the value, if any) */ -#define IW_POWER_ON 0x0000 /* No details... */ -#define IW_POWER_TYPE 0xF000 /* Type of parameter */ -#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ -#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ -#define IW_POWER_MODE 0x0F00 /* Power Management mode */ -#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ -#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ -#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ -#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ -#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ -#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ -#define IW_POWER_MIN 0x0001 /* Value is a minimum */ -#define IW_POWER_MAX 0x0002 /* Value is a maximum */ -#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ - -/* Transmit Power flags available */ -#define IW_TXPOW_TYPE 0x00FF /* Type of value */ -#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ -#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ -#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */ -#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ - -/* Retry limits and lifetime flags available */ -#define IW_RETRY_ON 0x0000 /* No details... */ -#define IW_RETRY_TYPE 0xF000 /* Type of parameter */ -#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ -#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ -#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */ -#define IW_RETRY_MIN 0x0001 /* Value is a minimum */ -#define IW_RETRY_MAX 0x0002 /* Value is a maximum */ -#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ -#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */ -#define IW_RETRY_LONG 0x0020 /* Value is for long packets */ - -/* Scanning request flags */ -#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ -#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ -#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ -#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ -#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ -#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ -#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ -#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ -#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ -/* struct iw_scan_req scan_type */ -#define IW_SCAN_TYPE_ACTIVE 0 -#define IW_SCAN_TYPE_PASSIVE 1 -/* Maximum size of returned data */ -#define IW_SCAN_MAX_DATA 4096 /* In bytes */ - -/* Scan capability flags - in (struct iw_range *)->scan_capa */ -#define IW_SCAN_CAPA_NONE 0x00 -#define IW_SCAN_CAPA_ESSID 0x01 -#define IW_SCAN_CAPA_BSSID 0x02 -#define IW_SCAN_CAPA_CHANNEL 0x04 -#define IW_SCAN_CAPA_MODE 0x08 -#define IW_SCAN_CAPA_RATE 0x10 -#define IW_SCAN_CAPA_TYPE 0x20 -#define IW_SCAN_CAPA_TIME 0x40 - -/* Max number of char in custom event - use multiple of them if needed */ -#define IW_CUSTOM_MAX 256 /* In bytes */ - -/* Generic information element */ -#define IW_GENERIC_IE_MAX 1024 - -/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ -#define IW_MLME_DEAUTH 0 -#define IW_MLME_DISASSOC 1 -#define IW_MLME_AUTH 2 -#define IW_MLME_ASSOC 3 - -/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ -#define IW_AUTH_INDEX 0x0FFF -#define IW_AUTH_FLAGS 0xF000 -/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) - * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the - * parameter that is being set/get to; value will be read/written to - * struct iw_param value field) */ -#define IW_AUTH_WPA_VERSION 0 -#define IW_AUTH_CIPHER_PAIRWISE 1 -#define IW_AUTH_CIPHER_GROUP 2 -#define IW_AUTH_KEY_MGMT 3 -#define IW_AUTH_TKIP_COUNTERMEASURES 4 -#define IW_AUTH_DROP_UNENCRYPTED 5 -#define IW_AUTH_80211_AUTH_ALG 6 -#define IW_AUTH_WPA_ENABLED 7 -#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 -#define IW_AUTH_ROAMING_CONTROL 9 -#define IW_AUTH_PRIVACY_INVOKED 10 -#define IW_AUTH_CIPHER_GROUP_MGMT 11 -#define IW_AUTH_MFP 12 - -/* IW_AUTH_WPA_VERSION values (bit field) */ -#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 -#define IW_AUTH_WPA_VERSION_WPA 0x00000002 -#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 - -/* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT - * values (bit field) */ -#define IW_AUTH_CIPHER_NONE 0x00000001 -#define IW_AUTH_CIPHER_WEP40 0x00000002 -#define IW_AUTH_CIPHER_TKIP 0x00000004 -#define IW_AUTH_CIPHER_CCMP 0x00000008 -#define IW_AUTH_CIPHER_WEP104 0x00000010 -#define IW_AUTH_CIPHER_AES_CMAC 0x00000020 - -/* IW_AUTH_KEY_MGMT values (bit field) */ -#define IW_AUTH_KEY_MGMT_802_1X 1 -#define IW_AUTH_KEY_MGMT_PSK 2 - -/* IW_AUTH_80211_AUTH_ALG values (bit field) */ -#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 -#define IW_AUTH_ALG_SHARED_KEY 0x00000002 -#define IW_AUTH_ALG_LEAP 0x00000004 - -/* IW_AUTH_ROAMING_CONTROL values */ -#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ -#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming - * control */ - -/* IW_AUTH_MFP (management frame protection) values */ -#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */ -#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */ -#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */ - -/* SIOCSIWENCODEEXT definitions */ -#define IW_ENCODE_SEQ_MAX_SIZE 8 -/* struct iw_encode_ext ->alg */ -#define IW_ENCODE_ALG_NONE 0 -#define IW_ENCODE_ALG_WEP 1 -#define IW_ENCODE_ALG_TKIP 2 -#define IW_ENCODE_ALG_CCMP 3 -#define IW_ENCODE_ALG_PMK 4 -#define IW_ENCODE_ALG_AES_CMAC 5 -/* struct iw_encode_ext ->ext_flags */ -#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 -#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 -#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 -#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 - -/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */ -#define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */ -#define IW_MICFAILURE_GROUP 0x00000004 -#define IW_MICFAILURE_PAIRWISE 0x00000008 -#define IW_MICFAILURE_STAKEY 0x00000010 -#define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported) - */ - -/* Bit field values for enc_capa in struct iw_range */ -#define IW_ENC_CAPA_WPA 0x00000001 -#define IW_ENC_CAPA_WPA2 0x00000002 -#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 -#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 -#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 - -/* Event capability macros - in (struct iw_range *)->event_capa - * Because we have more than 32 possible events, we use an array of - * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */ -#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \ - (cmd - SIOCIWFIRSTPRIV + 0x60) : \ - (cmd - SIOCIWFIRST)) -#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5) -#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F)) -/* Event capability constants - event autogenerated by the kernel - * This list is valid for most 802.11 devices, customise as needed... */ -#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \ - IW_EVENT_CAPA_MASK(0x8B06) | \ - IW_EVENT_CAPA_MASK(0x8B1A)) -#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A)) -/* "Easy" macro to set events in iw_range (less efficient) */ -#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd)) -#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; } - - -/****************************** TYPES ******************************/ - -/* --------------------------- SUBTYPES --------------------------- */ -/* - * Generic format for most parameters that fit in an int - */ -struct iw_param -{ - __s32 value; /* The value of the parameter itself */ - __u8 fixed; /* Hardware should not use auto select */ - __u8 disabled; /* Disable the feature */ - __u16 flags; /* Various specifc flags (if any) */ -}; - -/* - * For all data larger than 16 octets, we need to use a - * pointer to memory allocated in user space. - */ -struct iw_point -{ - void __user *pointer; /* Pointer to the data (in user space) */ - __u16 length; /* number of fields or size in bytes */ - __u16 flags; /* Optional params */ -}; - -#ifdef __KERNEL__ -#ifdef CONFIG_COMPAT - -#include <linux/compat.h> - -struct compat_iw_point { - compat_caddr_t pointer; - __u16 length; - __u16 flags; -}; -#endif -#endif - -/* - * A frequency - * For numbers lower than 10^9, we encode the number in 'm' and - * set 'e' to 0 - * For number greater than 10^9, we divide it by the lowest power - * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')... - * The power of 10 is in 'e', the result of the division is in 'm'. - */ -struct iw_freq -{ - __s32 m; /* Mantissa */ - __s16 e; /* Exponent */ - __u8 i; /* List index (when in range struct) */ - __u8 flags; /* Flags (fixed/auto) */ -}; - -/* - * Quality of the link - */ -struct iw_quality -{ - __u8 qual; /* link quality (%retries, SNR, - %missed beacons or better...) */ - __u8 level; /* signal level (dBm) */ - __u8 noise; /* noise level (dBm) */ - __u8 updated; /* Flags to know if updated */ -}; - -/* - * Packet discarded in the wireless adapter due to - * "wireless" specific problems... - * Note : the list of counter and statistics in net_device_stats - * is already pretty exhaustive, and you should use that first. - * This is only additional stats... - */ -struct iw_discarded -{ - __u32 nwid; /* Rx : Wrong nwid/essid */ - __u32 code; /* Rx : Unable to code/decode (WEP) */ - __u32 fragment; /* Rx : Can't perform MAC reassembly */ - __u32 retries; /* Tx : Max MAC retries num reached */ - __u32 misc; /* Others cases */ -}; - -/* - * Packet/Time period missed in the wireless adapter due to - * "wireless" specific problems... - */ -struct iw_missed -{ - __u32 beacon; /* Missed beacons/superframe */ -}; - -/* - * Quality range (for spy threshold) - */ -struct iw_thrspy -{ - struct sockaddr addr; /* Source address (hw/mac) */ - struct iw_quality qual; /* Quality of the link */ - struct iw_quality low; /* Low threshold */ - struct iw_quality high; /* High threshold */ -}; - -/* - * Optional data for scan request - * - * Note: these optional parameters are controlling parameters for the - * scanning behavior, these do not apply to getting scan results - * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and - * provide a merged results with all BSSes even if the previous scan - * request limited scanning to a subset, e.g., by specifying an SSID. - * Especially, scan results are required to include an entry for the - * current BSS if the driver is in Managed mode and associated with an AP. - */ -struct iw_scan_req -{ - __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */ - __u8 essid_len; - __u8 num_channels; /* num entries in channel_list; - * 0 = scan all allowed channels */ - __u8 flags; /* reserved as padding; use zero, this may - * be used in the future for adding flags - * to request different scan behavior */ - struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or - * individual address of a specific BSS */ - - /* - * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using - * the current ESSID. This allows scan requests for specific ESSID - * without having to change the current ESSID and potentially breaking - * the current association. - */ - __u8 essid[IW_ESSID_MAX_SIZE]; - - /* - * Optional parameters for changing the default scanning behavior. - * These are based on the MLME-SCAN.request from IEEE Std 802.11. - * TU is 1.024 ms. If these are set to 0, driver is expected to use - * reasonable default values. min_channel_time defines the time that - * will be used to wait for the first reply on each channel. If no - * replies are received, next channel will be scanned after this. If - * replies are received, total time waited on the channel is defined by - * max_channel_time. - */ - __u32 min_channel_time; /* in TU */ - __u32 max_channel_time; /* in TU */ - - struct iw_freq channel_list[IW_MAX_FREQUENCIES]; -}; - -/* ------------------------- WPA SUPPORT ------------------------- */ - -/* - * Extended data structure for get/set encoding (this is used with - * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_* - * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and - * only the data contents changes (key data -> this structure, including - * key data). - * - * If the new key is the first group key, it will be set as the default - * TX key. Otherwise, default TX key index is only changed if - * IW_ENCODE_EXT_SET_TX_KEY flag is set. - * - * Key will be changed with SIOCSIWENCODEEXT in all cases except for - * special "change TX key index" operation which is indicated by setting - * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY. - * - * tx_seq/rx_seq are only used when respective - * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal - * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start - * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally - * used only by an Authenticator (AP or an IBSS station) to get the - * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and - * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for - * debugging/testing. - */ -struct iw_encode_ext -{ - __u32 ext_flags; /* IW_ENCODE_EXT_* */ - __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ - __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ - struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast - * (group) keys or unicast address for - * individual keys */ - __u16 alg; /* IW_ENCODE_ALG_* */ - __u16 key_len; - __u8 key[0]; -}; - -/* SIOCSIWMLME data */ -struct iw_mlme -{ - __u16 cmd; /* IW_MLME_* */ - __u16 reason_code; - struct sockaddr addr; -}; - -/* SIOCSIWPMKSA data */ -#define IW_PMKSA_ADD 1 -#define IW_PMKSA_REMOVE 2 -#define IW_PMKSA_FLUSH 3 - -#define IW_PMKID_LEN 16 - -struct iw_pmksa -{ - __u32 cmd; /* IW_PMKSA_* */ - struct sockaddr bssid; - __u8 pmkid[IW_PMKID_LEN]; -}; - -/* IWEVMICHAELMICFAILURE data */ -struct iw_michaelmicfailure -{ - __u32 flags; - struct sockaddr src_addr; - __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ -}; - -/* IWEVPMKIDCAND data */ -#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */ -struct iw_pmkid_cand -{ - __u32 flags; /* IW_PMKID_CAND_* */ - __u32 index; /* the smaller the index, the higher the - * priority */ - struct sockaddr bssid; -}; - -/* ------------------------ WIRELESS STATS ------------------------ */ -/* - * Wireless statistics (used for /proc/net/wireless) - */ -struct iw_statistics -{ - __u16 status; /* Status - * - device dependent for now */ - - struct iw_quality qual; /* Quality of the link - * (instant/mean/max) */ - struct iw_discarded discard; /* Packet discarded counts */ - struct iw_missed miss; /* Packet missed counts */ -}; - -/* ------------------------ IOCTL REQUEST ------------------------ */ -/* - * This structure defines the payload of an ioctl, and is used - * below. - * - * Note that this structure should fit on the memory footprint - * of iwreq (which is the same as ifreq), which mean a max size of - * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... - * You should check this when increasing the structures defined - * above in this file... - */ -union iwreq_data -{ - /* Config - generic */ - char name[IFNAMSIZ]; - /* Name : used to verify the presence of wireless extensions. - * Name of the protocol/provider... */ - - struct iw_point essid; /* Extended network name */ - struct iw_param nwid; /* network id (or domain - the cell) */ - struct iw_freq freq; /* frequency or channel : - * 0-1000 = channel - * > 1000 = frequency in Hz */ - - struct iw_param sens; /* signal level threshold */ - struct iw_param bitrate; /* default bit rate */ - struct iw_param txpower; /* default transmit power */ - struct iw_param rts; /* RTS threshold threshold */ - struct iw_param frag; /* Fragmentation threshold */ - __u32 mode; /* Operation mode */ - struct iw_param retry; /* Retry limits & lifetime */ - - struct iw_point encoding; /* Encoding stuff : tokens */ - struct iw_param power; /* PM duration/timeout */ - struct iw_quality qual; /* Quality part of statistics */ - - struct sockaddr ap_addr; /* Access point address */ - struct sockaddr addr; /* Destination address (hw/mac) */ - - struct iw_param param; /* Other small parameters */ - struct iw_point data; /* Other large parameters */ -}; - -/* - * The structure to exchange data for ioctl. - * This structure is the same as 'struct ifreq', but (re)defined for - * convenience... - * Do I need to remind you about structure size (32 octets) ? - */ -struct iwreq -{ - union - { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ - } ifr_ifrn; - - /* Data part (defined just above) */ - union iwreq_data u; -}; - -/* -------------------------- IOCTL DATA -------------------------- */ -/* - * For those ioctl which want to exchange mode data that what could - * fit in the above structure... - */ - -/* - * Range of parameters - */ - -struct iw_range -{ - /* Informative stuff (to choose between different interface) */ - __u32 throughput; /* To give an idea... */ - /* In theory this value should be the maximum benchmarked - * TCP/IP throughput, because with most of these devices the - * bit rate is meaningless (overhead an co) to estimate how - * fast the connection will go and pick the fastest one. - * I suggest people to play with Netperf or any benchmark... - */ - - /* NWID (or domain id) */ - __u32 min_nwid; /* Minimal NWID we are able to set */ - __u32 max_nwid; /* Maximal NWID we are able to set */ - - /* Old Frequency (backward compat - moved lower ) */ - __u16 old_num_channels; - __u8 old_num_frequency; - - /* Scan capabilities */ - __u8 scan_capa; /* IW_SCAN_CAPA_* bit field */ - - /* Wireless event capability bitmasks */ - __u32 event_capa[6]; - - /* signal level threshold range */ - __s32 sensitivity; - - /* Quality of link & SNR stuff */ - /* Quality range (link, level, noise) - * If the quality is absolute, it will be in the range [0 ; max_qual], - * if the quality is dBm, it will be in the range [max_qual ; 0]. - * Don't forget that we use 8 bit arithmetics... */ - struct iw_quality max_qual; /* Quality of the link */ - /* This should contain the average/typical values of the quality - * indicator. This should be the threshold between a "good" and - * a "bad" link (example : monitor going from green to orange). - * Currently, user space apps like quality monitors don't have any - * way to calibrate the measurement. With this, they can split - * the range between 0 and max_qual in different quality level - * (using a geometric subdivision centered on the average). - * I expect that people doing the user space apps will feedback - * us on which value we need to put in each driver... */ - struct iw_quality avg_qual; /* Quality of the link */ - - /* Rates */ - __u8 num_bitrates; /* Number of entries in the list */ - __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ - - /* RTS threshold */ - __s32 min_rts; /* Minimal RTS threshold */ - __s32 max_rts; /* Maximal RTS threshold */ - - /* Frag threshold */ - __s32 min_frag; /* Minimal frag threshold */ - __s32 max_frag; /* Maximal frag threshold */ - - /* Power Management duration & timeout */ - __s32 min_pmp; /* Minimal PM period */ - __s32 max_pmp; /* Maximal PM period */ - __s32 min_pmt; /* Minimal PM timeout */ - __s32 max_pmt; /* Maximal PM timeout */ - __u16 pmp_flags; /* How to decode max/min PM period */ - __u16 pmt_flags; /* How to decode max/min PM timeout */ - __u16 pm_capa; /* What PM options are supported */ - - /* Encoder stuff */ - __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ - __u8 num_encoding_sizes; /* Number of entry in the list */ - __u8 max_encoding_tokens; /* Max number of tokens */ - /* For drivers that need a "login/passwd" form */ - __u8 encoding_login_index; /* token index for login token */ - - /* Transmit power */ - __u16 txpower_capa; /* What options are supported */ - __u8 num_txpower; /* Number of entries in the list */ - __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ - - /* Wireless Extension version info */ - __u8 we_version_compiled; /* Must be WIRELESS_EXT */ - __u8 we_version_source; /* Last update of source */ - - /* Retry limits and lifetime */ - __u16 retry_capa; /* What retry options are supported */ - __u16 retry_flags; /* How to decode max/min retry limit */ - __u16 r_time_flags; /* How to decode max/min retry life */ - __s32 min_retry; /* Minimal number of retries */ - __s32 max_retry; /* Maximal number of retries */ - __s32 min_r_time; /* Minimal retry lifetime */ - __s32 max_r_time; /* Maximal retry lifetime */ - - /* Frequency */ - __u16 num_channels; /* Number of channels [0; num - 1] */ - __u8 num_frequency; /* Number of entry in the list */ - struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ - /* Note : this frequency list doesn't need to fit channel numbers, - * because each entry contain its channel index */ - - __u32 enc_capa; /* IW_ENC_CAPA_* bit field */ -}; - -/* - * Private ioctl interface information - */ - -struct iw_priv_args -{ - __u32 cmd; /* Number of the ioctl to issue */ - __u16 set_args; /* Type and number of args */ - __u16 get_args; /* Type and number of args */ - char name[IFNAMSIZ]; /* Name of the extension */ -}; - -/* ----------------------- WIRELESS EVENTS ----------------------- */ -/* - * Wireless events are carried through the rtnetlink socket to user - * space. They are encapsulated in the IFLA_WIRELESS field of - * a RTM_NEWLINK message. - */ - -/* - * A Wireless Event. Contains basically the same data as the ioctl... - */ -struct iw_event -{ - __u16 len; /* Real length of this stuff */ - __u16 cmd; /* Wireless IOCTL */ - union iwreq_data u; /* IOCTL fixed payload */ -}; - -/* Size of the Event prefix (including padding and alignement junk) */ -#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) -/* Size of the various events */ -#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) -#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) -#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) -#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) -#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) -#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) - -/* iw_point events are special. First, the payload (extra data) come at - * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second, - * we omit the pointer, so start at an offset. */ -#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \ - (char *) NULL) -#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \ - IW_EV_POINT_OFF) - -#ifdef __KERNEL__ -#ifdef CONFIG_COMPAT -struct __compat_iw_event { - __u16 len; /* Real length of this stuff */ - __u16 cmd; /* Wireless IOCTL */ - compat_caddr_t pointer; -}; -#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer) -#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length) - -/* Size of the various events for compat */ -#define IW_EV_COMPAT_CHAR_LEN (IW_EV_COMPAT_LCP_LEN + IFNAMSIZ) -#define IW_EV_COMPAT_UINT_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(__u32)) -#define IW_EV_COMPAT_FREQ_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq)) -#define IW_EV_COMPAT_PARAM_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param)) -#define IW_EV_COMPAT_ADDR_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr)) -#define IW_EV_COMPAT_QUAL_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality)) -#define IW_EV_COMPAT_POINT_LEN \ - (IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \ - IW_EV_COMPAT_POINT_OFF) -#endif -#endif - -/* Size of the Event prefix when packed in stream */ -#define IW_EV_LCP_PK_LEN (4) -/* Size of the various events when packed in stream */ -#define IW_EV_CHAR_PK_LEN (IW_EV_LCP_PK_LEN + IFNAMSIZ) -#define IW_EV_UINT_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(__u32)) -#define IW_EV_FREQ_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_freq)) -#define IW_EV_PARAM_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_param)) -#define IW_EV_ADDR_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct sockaddr)) -#define IW_EV_QUAL_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_quality)) -#define IW_EV_POINT_PK_LEN (IW_EV_LCP_PK_LEN + 4) - -#endif /* _LINUX_WIRELESS_H */ diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c index 4de34a8..d3406f3 100644 --- a/src/eap_common/eap_fast_common.c +++ b/src/eap_common/eap_fast_common.c @@ -133,9 +133,9 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key " "expansion", keys.master_key, keys.master_key_len); - if (tls_prf(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, block_size + len)) + if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, + label, rnd, keys.client_random_len + + keys.server_random_len, out, block_size + len)) goto fail; os_free(rnd); os_memmove(out, out + block_size, len); diff --git a/src/eap_common/eap_peap_common.c b/src/eap_common/eap_peap_common.c index 3a64b8e..8a701d2 100644 --- a/src/eap_common/eap_peap_common.c +++ b/src/eap_common/eap_peap_common.c @@ -1,6 +1,6 @@ /* * EAP-PEAP common routines - * Copyright (c) 2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,9 +18,9 @@ #include "crypto/sha1.h" #include "eap_peap_common.h" -void peap_prfplus(int version, const u8 *key, size_t key_len, - const char *label, const u8 *seed, size_t seed_len, - u8 *buf, size_t buf_len) +int peap_prfplus(int version, const u8 *key, size_t key_len, + const char *label, const u8 *seed, size_t seed_len, + u8 *buf, size_t buf_len) { unsigned char counter = 0; size_t pos, plen; @@ -75,7 +75,8 @@ void peap_prfplus(int version, const u8 *key, size_t key_len, while (pos < buf_len) { counter++; plen = buf_len - pos; - hmac_sha1_vector(key, key_len, 5, addr, len, hash); + if (hmac_sha1_vector(key, key_len, 5, addr, len, hash) < 0) + return -1; if (plen >= SHA1_MAC_LEN) { os_memcpy(&buf[pos], hash, SHA1_MAC_LEN); pos += SHA1_MAC_LEN; @@ -85,4 +86,6 @@ void peap_prfplus(int version, const u8 *key, size_t key_len, } len[0] = SHA1_MAC_LEN; } + + return 0; } diff --git a/src/eap_common/eap_peap_common.h b/src/eap_common/eap_peap_common.h index f59afb0..f182078 100644 --- a/src/eap_common/eap_peap_common.h +++ b/src/eap_common/eap_peap_common.h @@ -1,6 +1,6 @@ /* * EAP-PEAP common routines - * Copyright (c) 2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -15,8 +15,8 @@ #ifndef EAP_PEAP_COMMON_H #define EAP_PEAP_COMMON_H -void peap_prfplus(int version, const u8 *key, size_t key_len, - const char *label, const u8 *seed, size_t seed_len, - u8 *buf, size_t buf_len); +int peap_prfplus(int version, const u8 *key, size_t key_len, + const char *label, const u8 *seed, size_t seed_len, + u8 *buf, size_t buf_len); #endif /* EAP_PEAP_COMMON_H */ diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c index c24b146..0dbdff2 100644 --- a/src/eap_common/eap_pwd_common.c +++ b/src/eap_common/eap_pwd_common.c @@ -75,8 +75,8 @@ void eap_pwd_kdf(u8 *key, int keylen, u8 *label, int labellen, /* since we're expanding to a bit length, mask off the excess */ if (resultbitlen % 8) { - mask >>= ((resultbytelen * 8) - resultbitlen); - result[0] &= mask; + mask <<= (8 - (resultbitlen % 8)); + result[resultbytelen - 1] &= mask; } } @@ -189,6 +189,18 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, prfbuf, primebitlen); BN_bin2bn(prfbuf, primebytelen, x_candidate); + + /* + * eap_pwd_kdf() returns a string of bits 0..primebitlen but + * BN_bin2bn will treat that string of bits as a big endian + * number. If the primebitlen is not an even multiple of 8 + * then excessive bits-- those _after_ primebitlen-- so now + * we have to shift right the amount we masked off. + */ + if (primebitlen % 8) + BN_rshift(x_candidate, x_candidate, + (8 - (primebitlen % 8))); + if (BN_ucmp(x_candidate, grp->prime) >= 0) continue; @@ -272,6 +284,7 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k, u8 mk[SHA256_DIGEST_LENGTH], *cruft; u8 session_id[SHA256_DIGEST_LENGTH + 1]; u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN]; + int offset; if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL) return -1; @@ -283,16 +296,21 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k, session_id[0] = EAP_TYPE_PWD; H_Init(&ctx); H_Update(&ctx, (u8 *)ciphersuite, sizeof(u32)); - BN_bn2bin(peer_scalar, cruft); + offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar); + os_memset(cruft, 0, BN_num_bytes(grp->prime)); + BN_bn2bin(peer_scalar, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(grp->order)); - BN_bn2bin(server_scalar, cruft); + offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar); + os_memset(cruft, 0, BN_num_bytes(grp->prime)); + BN_bn2bin(server_scalar, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(grp->order)); H_Final(&ctx, &session_id[1]); /* then compute MK = H(k | commit-peer | commit-server) */ H_Init(&ctx); + offset = BN_num_bytes(grp->prime) - BN_num_bytes(k); os_memset(cruft, 0, BN_num_bytes(grp->prime)); - BN_bn2bin(k, cruft); + BN_bn2bin(k, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(grp->prime)); H_Update(&ctx, commit_peer, SHA256_DIGEST_LENGTH); H_Update(&ctx, commit_server, SHA256_DIGEST_LENGTH); diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h index 971386d..4b841b7 100644 --- a/src/eap_common/eap_pwd_common.h +++ b/src/eap_common/eap_pwd_common.h @@ -35,13 +35,8 @@ typedef struct group_definition_ { /* * EAP-pwd header, included on all payloads + * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set) */ -struct eap_pwd_hdr { - u8 l_bit:1; - u8 m_bit:1; - u8 exch:6; - u8 total_length[0]; /* included when l_bit is set */ -} STRUCT_PACKED; #define EAP_PWD_OPCODE_ID_EXCH 1 #define EAP_PWD_OPCODE_COMMIT_EXCH 2 diff --git a/src/eap_common/ikev2_common.h b/src/eap_common/ikev2_common.h index c96a070..31a2b0d 100644 --- a/src/eap_common/ikev2_common.h +++ b/src/eap_common/ikev2_common.h @@ -139,7 +139,7 @@ enum { IKEV2_TRANSFORM_ESN = 5 }; -/* IKEv2 Tranform Type 1 (Encryption Algorithm) */ +/* IKEv2 Transform Type 1 (Encryption Algorithm) */ enum { ENCR_DES_IV64 = 1, ENCR_DES = 2, diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index ecfaf30..91fa4a9 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -147,6 +147,7 @@ SM_STATE(EAP, INITIALIZE) sm->methodState = METHOD_NONE; sm->allowNotifications = TRUE; sm->decision = DECISION_FAIL; + sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT; eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout); eapol_set_bool(sm, EAPOL_eapSuccess, FALSE); eapol_set_bool(sm, EAPOL_eapFail, FALSE); @@ -1242,6 +1243,7 @@ struct eap_sm * eap_peer_sm_init(void *eapol_ctx, #endif /* CONFIG_FIPS */ tlsconf.event_cb = eap_peer_sm_tls_event; tlsconf.cb_ctx = sm; + tlsconf.cert_in_cb = conf->cert_in_cb; sm->ssl_ctx = tls_init(&tlsconf); if (sm->ssl_ctx == NULL) { wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS " @@ -1466,16 +1468,11 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose) #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -typedef enum { - TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD, - TYPE_PASSPHRASE -} eap_ctrl_req_type; - -static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type, +static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field, const char *msg, size_t msglen) { struct eap_peer_config *config; - char *field, *txt, *tmp; + char *txt = NULL, *tmp; if (sm == NULL) return; @@ -1483,29 +1480,20 @@ static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type, if (config == NULL) return; - switch (type) { - case TYPE_IDENTITY: - field = "IDENTITY"; - txt = "Identity"; + switch (field) { + case WPA_CTRL_REQ_EAP_IDENTITY: config->pending_req_identity++; break; - case TYPE_PASSWORD: - field = "PASSWORD"; - txt = "Password"; + case WPA_CTRL_REQ_EAP_PASSWORD: config->pending_req_password++; break; - case TYPE_NEW_PASSWORD: - field = "NEW_PASSWORD"; - txt = "New Password"; + case WPA_CTRL_REQ_EAP_NEW_PASSWORD: config->pending_req_new_password++; break; - case TYPE_PIN: - field = "PIN"; - txt = "PIN"; + case WPA_CTRL_REQ_EAP_PIN: config->pending_req_pin++; break; - case TYPE_OTP: - field = "OTP"; + case WPA_CTRL_REQ_EAP_OTP: if (msg) { tmp = os_malloc(msglen + 3); if (tmp == NULL) @@ -1524,9 +1512,7 @@ static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type, txt = config->pending_req_otp; } break; - case TYPE_PASSPHRASE: - field = "PASSPHRASE"; - txt = "Private key passphrase"; + case WPA_CTRL_REQ_EAP_PASSPHRASE: config->pending_req_passphrase++; break; default: @@ -1559,7 +1545,7 @@ const char * eap_sm_get_method_name(struct eap_sm *sm) */ void eap_sm_request_identity(struct eap_sm *sm) { - eap_sm_request(sm, TYPE_IDENTITY, NULL, 0); + eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0); } @@ -1574,7 +1560,7 @@ void eap_sm_request_identity(struct eap_sm *sm) */ void eap_sm_request_password(struct eap_sm *sm) { - eap_sm_request(sm, TYPE_PASSWORD, NULL, 0); + eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0); } @@ -1589,7 +1575,7 @@ void eap_sm_request_password(struct eap_sm *sm) */ void eap_sm_request_new_password(struct eap_sm *sm) { - eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0); + eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0); } @@ -1604,7 +1590,7 @@ void eap_sm_request_new_password(struct eap_sm *sm) */ void eap_sm_request_pin(struct eap_sm *sm) { - eap_sm_request(sm, TYPE_PIN, NULL, 0); + eap_sm_request(sm, WPA_CTRL_REQ_EAP_PIN, NULL, 0); } @@ -1620,7 +1606,7 @@ void eap_sm_request_pin(struct eap_sm *sm) */ void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len) { - eap_sm_request(sm, TYPE_OTP, msg, msg_len); + eap_sm_request(sm, WPA_CTRL_REQ_EAP_OTP, msg, msg_len); } @@ -1635,7 +1621,7 @@ void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len) */ void eap_sm_request_passphrase(struct eap_sm *sm) { - eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0); + eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSPHRASE, NULL, 0); } diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h index 2a80d4e..f35197f 100644 --- a/src/eap_peer/eap.h +++ b/src/eap_peer/eap.h @@ -216,10 +216,10 @@ struct eapol_callbacks { /** * eap_param_needed - Notify that EAP parameter is needed * @ctx: eapol_ctx from eap_peer_sm_init() call - * @field: Field name (e.g., "IDENTITY") + * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY) * @txt: User readable text describing the required parameter */ - void (*eap_param_needed)(void *ctx, const char *field, + void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field, const char *txt); /** @@ -262,6 +262,11 @@ struct eap_config { * This is only used by EAP-WSC and can be left %NULL if not available. */ struct wps_context *wps; + + /** + * cert_in_cb - Include server certificates in callback + */ + int cert_in_cb; }; struct eap_sm * eap_peer_sm_init(void *eapol_ctx, diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c index 182f01a..766764b 100644 --- a/src/eap_peer/eap_aka.c +++ b/src/eap_peer/eap_aka.c @@ -235,21 +235,20 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data) static void eap_aka_clear_identities(struct eap_aka_data *data, int id) { - wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s", - id & CLEAR_PSEUDONYM ? " pseudonym" : "", - id & CLEAR_REAUTH_ID ? " reauth_id" : "", - id & CLEAR_EAP_ID ? " eap_id" : ""); if (id & CLEAR_PSEUDONYM) { + wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym"); os_free(data->pseudonym); data->pseudonym = NULL; data->pseudonym_len = 0; } if (id & CLEAR_REAUTH_ID) { + wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id"); os_free(data->reauth_id); data->reauth_id = NULL; data->reauth_id_len = 0; } if (id & CLEAR_EAP_ID) { + wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id"); os_free(data->last_eap_identity); data->last_eap_identity = NULL; data->last_eap_identity_len = 0; @@ -880,11 +879,11 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } - /* Old reauthentication and pseudonym identities must not be used - * anymore. In other words, if no new identities are received, full - * authentication will be used on next reauthentication. */ - eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID | - CLEAR_EAP_ID); + /* Old reauthentication identity must not be used anymore. In + * other words, if no new identities are received, full + * authentication will be used on next reauthentication (using + * pseudonym identity or permanent identity). */ + eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); if (attr->encr_data) { u8 *decrypted; diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c index 5d3e69d..3cfb41a 100644 --- a/src/eap_peer/eap_fast.c +++ b/src/eap_peer/eap_fast.c @@ -444,8 +444,9 @@ static int eap_fast_phase2_request(struct eap_sm *sm, return 0; } - if (data->phase2_priv == NULL && - eap_fast_init_phase2_method(sm, data) < 0) { + if ((data->phase2_priv == NULL && + eap_fast_init_phase2_method(sm, data) < 0) || + data->phase2_method == NULL) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize " "Phase 2 EAP method %d", *pos); ret->methodState = METHOD_DONE; @@ -542,7 +543,7 @@ static struct wpabuf * eap_fast_tlv_pac_ack(void) static struct wpabuf * eap_fast_process_eap_payload_tlv( struct eap_sm *sm, struct eap_fast_data *data, - struct eap_method_ret *ret, const struct eap_hdr *req, + struct eap_method_ret *ret, u8 *eap_payload_tlv, size_t eap_payload_tlv_len) { struct eap_hdr *hdr; @@ -1037,11 +1038,15 @@ static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm, } else { /* * This is PAC refreshing, i.e., normal authentication that is - * expected to be completed with an EAP-Success. + * expected to be completed with an EAP-Success. However, + * RFC 5422, Section 3.5 allows EAP-Failure to be sent even + * after protected success exchange in case of EAP-Fast + * provisioning, so we better use DECISION_COND_SUCC here + * instead of DECISION_UNCOND_SUCC. */ wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV " "- PAC refreshing completed successfully"); - ret->decision = DECISION_UNCOND_SUCC; + ret->decision = DECISION_COND_SUCC; } ret->methodState = METHOD_DONE; return eap_fast_tlv_pac_ack(); @@ -1184,7 +1189,7 @@ static int eap_fast_process_decrypted(struct eap_sm *sm, if (tlv.eap_payload_tlv) { tmp = eap_fast_process_eap_payload_tlv( - sm, data, ret, req, tlv.eap_payload_tlv, + sm, data, ret, tlv.eap_payload_tlv, tlv.eap_payload_tlv_len); resp = wpabuf_concat(resp, tmp); } diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c index 3b0af05..937fd45 100644 --- a/src/eap_peer/eap_methods.c +++ b/src/eap_peer/eap_methods.c @@ -77,6 +77,8 @@ EapType eap_peer_get_type(const char *name, int *vendor) const char * eap_get_name(int vendor, EapType type) { struct eap_method *m; + if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED) + return "expanded"; for (m = eap_methods; m; m = m->next) { if (m->vendor == vendor && m->method == type) return m->name; diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c index 2b72084..7cb8213 100644 --- a/src/eap_peer/eap_peap.c +++ b/src/eap_peer/eap_peap.c @@ -196,7 +196,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv) * @nak_type: TLV type (EAP_TLV_*) * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure * - * This funtion builds an EAP-TLV NAK message. The caller is responsible for + * This function builds an EAP-TLV NAK message. The caller is responsible for * freeing the returned buffer. */ static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type) @@ -285,8 +285,10 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) * in the end of the label just before ISK; is that just a typo?) */ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); - peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys", - isk, sizeof(isk), imck, sizeof(imck)); + if (peap_prfplus(data->peap_version, tk, 40, + "Inner Methods Compound Keys", + isk, sizeof(isk), imck, sizeof(imck)) < 0) + return -1; wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", imck, sizeof(imck)); @@ -346,8 +348,8 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm, * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE) * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure * - * This funtion builds an EAP-TLV Result message. The caller is responsible for - * freeing the returned buffer. + * This function builds an EAP-TLV Result message. The caller is responsible + * for freeing the returned buffer. */ static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm, struct eap_peap_data *data, @@ -1247,9 +1249,12 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) * termination for this label while the one used for deriving * IPMK|CMK did not use null termination. */ - peap_prfplus(data->peap_version, data->ipmk, 40, - "Session Key Generating Function", - (u8 *) "\00", 1, csk, sizeof(csk)); + if (peap_prfplus(data->peap_version, data->ipmk, 40, + "Session Key Generating Function", + (u8 *) "\00", 1, csk, sizeof(csk)) < 0) { + os_free(key); + return NULL; + } wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); os_memcpy(key, csk, EAP_TLS_KEY_LEN); wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c index e4705b7..1957c82 100644 --- a/src/eap_peer/eap_pwd.c +++ b/src/eap_peer/eap_pwd.c @@ -423,8 +423,7 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, - sizeof(struct eap_pwd_hdr) + - BN_num_bytes(data->grp->order) + + 1 + BN_num_bytes(data->grp->order) + (2 * BN_num_bytes(data->grp->prime)), EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp == NULL) @@ -465,6 +464,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, u32 cs; u16 grp; u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr; + int offset; /* * first build up the ciphersuite which is group | random_function | @@ -497,7 +497,8 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, * value may start with a few zeros and the previous one did not. */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->k, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); + BN_bn2bin(data->k, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* server element: x, y */ @@ -509,15 +510,19 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, goto fin; } os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(x, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(y, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* server scalar */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->server_scalar, cruft); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->server_scalar); + BN_bn2bin(data->server_scalar, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); /* my element: x, y */ @@ -530,15 +535,19 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, } os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(x, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(y, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* my scalar */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->my_scalar, cruft); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->my_scalar); + BN_bn2bin(data->my_scalar, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); /* the ciphersuite */ @@ -564,7 +573,8 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, /* k */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->k, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); + BN_bn2bin(data->k, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* my element */ @@ -576,15 +586,19 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, goto fin; } os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(x, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(y, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* my scalar */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->my_scalar, cruft); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->my_scalar); + BN_bn2bin(data->my_scalar, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); /* server element: x, y */ @@ -596,15 +610,19 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, goto fin; } os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(x, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(y, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* server scalar */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->server_scalar, cruft); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->server_scalar); + BN_bn2bin(data->server_scalar, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); /* the ciphersuite */ @@ -614,7 +632,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, H_Final(&ctx, conf); resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, - sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH, + 1 + SHA256_DIGEST_LENGTH, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp == NULL) goto fin; diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c index 6677063..06fbc5b 100644 --- a/src/eap_peer/eap_sim.c +++ b/src/eap_peer/eap_sim.c @@ -266,21 +266,20 @@ static int eap_sim_supported_ver(int version) static void eap_sim_clear_identities(struct eap_sim_data *data, int id) { - wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old%s%s%s", - id & CLEAR_PSEUDONYM ? " pseudonym" : "", - id & CLEAR_REAUTH_ID ? " reauth_id" : "", - id & CLEAR_EAP_ID ? " eap_id" : ""); - if (id & CLEAR_PSEUDONYM) { + if ((id & CLEAR_PSEUDONYM) && data->pseudonym) { + wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym"); os_free(data->pseudonym); data->pseudonym = NULL; data->pseudonym_len = 0; } - if (id & CLEAR_REAUTH_ID) { + if ((id & CLEAR_REAUTH_ID) && data->reauth_id) { + wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id"); os_free(data->reauth_id); data->reauth_id = NULL; data->reauth_id_len = 0; } - if (id & CLEAR_EAP_ID) { + if ((id & CLEAR_EAP_ID) && data->last_eap_identity) { + wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id"); os_free(data->last_eap_identity); data->last_eap_identity = NULL; data->last_eap_identity_len = 0; @@ -649,11 +648,11 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } - /* Old reauthentication and pseudonym identities must not be used - * anymore. In other words, if no new identities are received, full - * authentication will be used on next reauthentication. */ - eap_sim_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID | - CLEAR_EAP_ID); + /* Old reauthentication identity must not be used anymore. In + * other words, if no new reauth identity is received, full + * authentication will be used on next reauthentication (using + * pseudonym identity or permanent identity). */ + eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); if (attr->encr_data) { u8 *decrypted; diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c index d1567e9..2934ba4 100644 --- a/src/eap_peer/eap_tls_common.c +++ b/src/eap_peer/eap_tls_common.c @@ -112,7 +112,6 @@ static int eap_tls_params_from_conf(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "TLS: using phase1 config options"); eap_tls_params_from_conf1(params, config); } - params->tls_ia = data->tls_ia; /* * Use blob data, if available. Otherwise, leave reference to external @@ -295,9 +294,9 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, os_memcpy(rnd + keys.client_random_len, keys.server_random, keys.server_random_len); - if (tls_prf(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, len)) + if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, + label, rnd, keys.client_random_len + + keys.server_random_len, out, len)) goto fail; os_free(rnd); diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h index e9e0998..e9a07b8 100644 --- a/src/eap_peer/eap_tls_common.h +++ b/src/eap_peer/eap_tls_common.h @@ -66,11 +66,6 @@ struct eap_ssl_data { int include_tls_length; /** - * tls_ia - Whether TLS/IA is enabled for this TLS connection - */ - int tls_ia; - - /** * eap - EAP state machine allocated with eap_peer_sm_init() */ struct eap_sm *eap; diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c index 6c95f72..da288eb 100644 --- a/src/eap_peer/eap_tnc.c +++ b/src/eap_peer/eap_tnc.c @@ -15,7 +15,6 @@ #include "includes.h" #include "common.h" -#include "base64.h" #include "eap_i.h" #include "tncc.h" diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c index e8f0f38..612dfa7 100644 --- a/src/eap_peer/eap_ttls.c +++ b/src/eap_peer/eap_ttls.c @@ -1,6 +1,6 @@ /* * EAP peer method: EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,17 +26,7 @@ #include "eap_config.h" -/* Maximum supported TTLS version - * 0 = RFC 5281 - * 1 = draft-funk-eap-ttls-v1-00.txt - */ -#ifndef EAP_TTLS_VERSION -#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */ -#endif /* EAP_TTLS_VERSION */ - - -#define MSCHAPV2_KEY_LEN 16 -#define MSCHAPV2_NT_RESPONSE_LEN 24 +#define EAP_TTLS_VERSION 0 static void eap_ttls_deinit(struct eap_sm *sm, void *priv); @@ -44,9 +34,8 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv); struct eap_ttls_data { struct eap_ssl_data ssl; - int ssl_initialized; - int ttls_version, force_ttls_version; + int ttls_version; const struct eap_method *phase2_method; void *phase2_priv; @@ -91,22 +80,9 @@ static void * eap_ttls_init(struct eap_sm *sm) if (data == NULL) return NULL; data->ttls_version = EAP_TTLS_VERSION; - data->force_ttls_version = -1; selected = "EAP"; data->phase2_type = EAP_TTLS_PHASE2_EAP; -#if EAP_TTLS_VERSION > 0 - if (config && config->phase1) { - const char *pos = os_strstr(config->phase1, "ttlsver="); - if (pos) { - data->force_ttls_version = atoi(pos + 8); - data->ttls_version = data->force_ttls_version; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version " - "%d", data->force_ttls_version); - } - } -#endif /* EAP_TTLS_VERSION */ - if (config && config->phase2) { if (os_strstr(config->phase2, "autheap=")) { selected = "EAP"; @@ -140,19 +116,11 @@ static void * eap_ttls_init(struct eap_sm *sm) data->phase2_eap_type.method = EAP_TYPE_NONE; } -#if EAP_TTLS_VERSION > 0 - if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) && - data->ttls_version > 0) { - if (data->force_ttls_version > 0) { - wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and " - "TLS library does not support TLS/IA.", - data->force_ttls_version); - eap_ttls_deinit(sm, data); - return NULL; - } - data->ttls_version = 0; + if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) { + wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); + eap_ttls_deinit(sm, data); + return NULL; } -#endif /* EAP_TTLS_VERSION */ return data; } @@ -176,8 +144,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv) return; eap_ttls_phase2_eap_deinit(sm, data); os_free(data->phase2_eap_types); - if (data->ssl_initialized) - eap_peer_tls_ssl_deinit(sm, &data->ssl); + eap_peer_tls_ssl_deinit(sm, &data->ssl); os_free(data->key_data); wpabuf_free(data->pending_phase2_req); os_free(data); @@ -246,39 +213,6 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, } -#if EAP_TTLS_VERSION > 0 -static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm, - struct eap_ttls_data *data, - const u8 *key, size_t key_len) -{ - u8 *buf; - size_t buf_len; - int ret; - - if (key) { - buf_len = 2 + key_len; - buf = os_malloc(buf_len); - if (buf == NULL) - return -1; - WPA_PUT_BE16(buf, key_len); - os_memcpy(buf + 2, key, key_len); - } else { - buf = NULL; - buf_len = 0; - } - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner " - "secret permutation", buf, buf_len); - ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx, - data->ssl.conn, - buf, buf_len); - os_free(buf); - - return ret; -} -#endif /* EAP_TTLS_VERSION */ - - static int eap_ttls_v0_derive_key(struct eap_sm *sm, struct eap_ttls_data *data) { @@ -298,156 +232,10 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm, } -#if EAP_TTLS_VERSION > 0 -static int eap_ttls_v1_derive_key(struct eap_sm *sm, - struct eap_ttls_data *data) -{ - struct tls_keys keys; - u8 *rnd; - - os_free(data->key_data); - data->key_data = NULL; - - os_memset(&keys, 0, sizeof(keys)); - if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || - keys.client_random == NULL || keys.server_random == NULL || - keys.inner_secret == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " - "client random, or server random to derive keying " - "material"); - return -1; - } - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - data->key_data = os_malloc(EAP_TLS_KEY_LEN); - if (rnd == NULL || data->key_data == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation"); - os_free(rnd); - os_free(data->key_data); - data->key_data = NULL; - return -1; - } - os_memcpy(rnd, keys.client_random, keys.client_random_len); - os_memcpy(rnd + keys.client_random_len, keys.server_random, - keys.server_random_len); - - if (tls_prf(keys.inner_secret, keys.inner_secret_len, - "ttls v1 keying material", rnd, keys.client_random_len + - keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); - os_free(rnd); - os_free(data->key_data); - data->key_data = NULL; - return -1; - } - - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random", - rnd, keys.client_random_len + keys.server_random_len); - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret", - keys.inner_secret, keys.inner_secret_len); - - os_free(rnd); - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", - data->key_data, EAP_TLS_KEY_LEN); - - return 0; -} -#endif /* EAP_TTLS_VERSION */ - - static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, struct eap_ttls_data *data, size_t len) { -#if EAP_TTLS_VERSION > 0 - struct tls_keys keys; - u8 *challenge, *rnd; -#endif /* EAP_TTLS_VERSION */ - - if (data->ttls_version == 0) { - return eap_peer_tls_derive_key(sm, &data->ssl, - "ttls challenge", len); - } - -#if EAP_TTLS_VERSION > 0 - - os_memset(&keys, 0, sizeof(keys)); - if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || - keys.client_random == NULL || keys.server_random == NULL || - keys.inner_secret == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " - "client random, or server random to derive " - "implicit challenge"); - return NULL; - } - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - challenge = os_malloc(len); - if (rnd == NULL || challenge == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit " - "challenge derivation"); - os_free(rnd); - os_free(challenge); - return NULL; - } - os_memcpy(rnd, keys.server_random, keys.server_random_len); - os_memcpy(rnd + keys.server_random_len, keys.client_random, - keys.client_random_len); - - if (tls_prf(keys.inner_secret, keys.inner_secret_len, - "inner application challenge", rnd, - keys.client_random_len + keys.server_random_len, - challenge, len)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit " - "challenge"); - os_free(rnd); - os_free(challenge); - return NULL; - } - - os_free(rnd); - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge", - challenge, len); - - return challenge; - -#else /* EAP_TTLS_VERSION */ - - return NULL; - -#endif /* EAP_TTLS_VERSION */ -} - - -static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret) -{ -#if EAP_TTLS_VERSION > 0 - if (data->ttls_version > 0) { - const struct eap_method *m = data->phase2_method; - void *priv = data->phase2_priv; - - /* TTLSv1 requires TLS/IA FinalPhaseFinished */ - if (ret->decision == DECISION_UNCOND_SUCC) - ret->decision = DECISION_COND_SUCC; - ret->methodState = METHOD_CONT; - - if (ret->decision == DECISION_COND_SUCC && - m->isKeyAvailable && m->getKey && - m->isKeyAvailable(sm, priv)) { - u8 *key; - size_t key_len; - key = m->getKey(sm, priv, &key_len); - if (key) { - eap_ttls_ia_permute_inner_secret( - sm, data, key, key_len); - os_free(key); - } - } - } -#endif /* EAP_TTLS_VERSION */ + return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len); } @@ -494,7 +282,6 @@ static int eap_ttls_phase2_eap_process(struct eap_sm *sm, ret->methodState = iret.methodState; ret->decision = iret.decision; } - eap_ttlsv1_phase2_eap_finish(sm, data, ret); return 0; } @@ -615,26 +402,6 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm, } -static void eap_ttlsv1_permute_inner(struct eap_sm *sm, - struct eap_ttls_data *data) -{ -#if EAP_TTLS_VERSION > 0 - u8 session_key[2 * MSCHAPV2_KEY_LEN]; - - if (data->ttls_version == 0) - return; - - get_asymetric_start_key(data->master_key, session_key, - MSCHAPV2_KEY_LEN, 0, 0); - get_asymetric_start_key(data->master_key, - session_key + MSCHAPV2_KEY_LEN, - MSCHAPV2_KEY_LEN, 1, 0); - eap_ttls_ia_permute_inner_secret(sm, data, session_key, - sizeof(session_key)); -#endif /* EAP_TTLS_VERSION */ -} - - static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, @@ -702,8 +469,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, } data->auth_response_valid = 1; - eap_ttlsv1_permute_inner(sm, data); - pos += 24; os_free(challenge); AVP_PAD(buf, pos); @@ -711,7 +476,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, wpabuf_put(msg, pos - buf); *resp = msg; - if (sm->workaround && data->ttls_version == 0) { + if (sm->workaround) { /* At least FreeRADIUS seems to be terminating * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success * packet. */ @@ -798,17 +563,10 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, wpabuf_put(msg, pos - buf); *resp = msg; - if (data->ttls_version > 0) { - /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, - * so do not allow connection to be terminated yet. */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - /* EAP-TTLS/MSCHAP does not provide tunneled success - * notification, so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - } + /* EAP-TTLS/MSCHAP does not provide tunneled success + * notification, so assume that Phase2 succeeds. */ + ret->methodState = METHOD_DONE; + ret->decision = DECISION_COND_SUCC; return 0; } @@ -859,17 +617,10 @@ static int eap_ttls_phase2_request_pap(struct eap_sm *sm, wpabuf_put(msg, pos - buf); *resp = msg; - if (data->ttls_version > 0) { - /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, - * so do not allow connection to be terminated yet. */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - /* EAP-TTLS/PAP does not provide tunneled success notification, - * so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - } + /* EAP-TTLS/PAP does not provide tunneled success notification, + * so assume that Phase2 succeeds. */ + ret->methodState = METHOD_DONE; + ret->decision = DECISION_COND_SUCC; return 0; } @@ -942,17 +693,10 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm, wpabuf_put(msg, pos - buf); *resp = msg; - if (data->ttls_version > 0) { - /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, - * so do not allow connection to be terminated yet. */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - /* EAP-TTLS/CHAP does not provide tunneled success - * notification, so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - } + /* EAP-TTLS/CHAP does not provide tunneled success + * notification, so assume that Phase2 succeeds. */ + ret->methodState = METHOD_DONE; + ret->decision = DECISION_COND_SUCC; return 0; } @@ -1027,36 +771,6 @@ static int eap_ttls_phase2_request(struct eap_sm *sm, } -#if EAP_TTLS_VERSION > 0 -static struct wpabuf * eap_ttls_build_phase_finished( - struct eap_sm *sm, struct eap_ttls_data *data, int id, int final) -{ - struct wpabuf *req, *buf; - - buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx, - data->ssl.conn, - final); - if (buf == NULL) - return NULL; - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, - 1 + wpabuf_len(buf), - EAP_CODE_RESPONSE, id); - if (req == NULL) { - wpabuf_free(buf); - return NULL; - } - - wpabuf_put_u8(req, data->ttls_version); - wpabuf_put_buf(req, buf); - wpabuf_free(buf); - eap_update_len(req); - - return req; -} -#endif /* EAP_TTLS_VERSION */ - - struct ttls_parse_avp { u8 *mschapv2; u8 *eapdata; @@ -1366,19 +1080,9 @@ static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " "authentication succeeded"); - if (data->ttls_version > 0) { - /* - * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report - * success, so do not allow connection to be terminated - * yet. - */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - data->phase2_success = 1; - } + ret->methodState = METHOD_DONE; + ret->decision = DECISION_UNCOND_SUCC; + data->phase2_success = 1; /* * Reply with empty data; authentication server will reply @@ -1493,24 +1197,6 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm, } -#if EAP_TTLS_VERSION > 0 -static void eap_ttls_final_phase_finished(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - u8 identifier, - struct wpabuf **out_data) -{ - wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received"); - wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - data->phase2_success = 1; - *out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1); - eap_ttls_v1_derive_key(sm, data); -} -#endif /* EAP_TTLS_VERSION */ - - static int eap_ttls_implicit_identity_request(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, @@ -1534,6 +1220,21 @@ static int eap_ttls_implicit_identity_request(struct eap_sm *sm, "processing failed"); retval = -1; } else { + struct eap_peer_config *config = eap_get_config(sm); + if (resp == NULL && + (config->pending_req_identity || + config->pending_req_password || + config->pending_req_otp || + config->pending_req_new_password)) { + /* + * Use empty buffer to force implicit request + * processing when EAP request is re-processed after + * user input. + */ + wpabuf_free(data->pending_phase2_req); + data->pending_phase2_req = wpabuf_alloc(0); + } + retval = eap_ttls_encrypt_response(sm, data, resp, identifier, out_data); } @@ -1627,17 +1328,6 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, if (retval) goto done; -#if EAP_TTLS_VERSION > 0 - if (data->ttls_version > 0 && - (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) && - tls_connection_ia_final_phase_finished(sm->ssl_ctx, - data->ssl.conn)) { - eap_ttls_final_phase_finished(sm, data, ret, identifier, - out_data); - goto done; - } -#endif /* EAP_TTLS_VERSION */ - continue_req: data->phase2_start = 0; @@ -1662,46 +1352,6 @@ done: } -static int eap_ttls_process_start(struct eap_sm *sm, - struct eap_ttls_data *data, u8 flags, - struct eap_method_ret *ret) -{ - struct eap_peer_config *config = eap_get_config(sm); - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)", - flags & EAP_TLS_VERSION_MASK, data->ttls_version); -#if EAP_TTLS_VERSION > 0 - if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version) - data->ttls_version = flags & EAP_TLS_VERSION_MASK; - if (data->force_ttls_version >= 0 && - data->force_ttls_version != data->ttls_version) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select " - "forced TTLS version %d", - data->force_ttls_version); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d", - data->ttls_version); - - if (data->ttls_version > 0) - data->ssl.tls_ia = 1; -#endif /* EAP_TTLS_VERSION */ - if (!data->ssl_initialized && - eap_peer_tls_ssl_init(sm, &data->ssl, config)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); - return -1; - } - data->ssl_initialized = 1; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start"); - - return 0; -} - - static int eap_ttls_process_handshake(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, @@ -1725,8 +1375,7 @@ static int eap_ttls_process_handshake(struct eap_sm *sm, ret->methodState = METHOD_MAY_CONT; } data->phase2_start = 1; - if (data->ttls_version == 0) - eap_ttls_v0_derive_key(sm, data); + eap_ttls_v0_derive_key(sm, data); if (*out_data == NULL || wpabuf_len(*out_data) == 0) { if (eap_ttls_decrypt(sm, data, ret, identifier, @@ -1761,7 +1410,7 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret) { - if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) { + if (ret->methodState == METHOD_DONE) { ret->allowNotifications = FALSE; if (ret->decision == DECISION_UNCOND_SUCC || ret->decision == DECISION_COND_SUCC) { @@ -1779,8 +1428,7 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm, } #endif /* EAP_TNC */ } - } else if (data->ttls_version == 0 && - ret->methodState == METHOD_MAY_CONT && + } else if (ret->methodState == METHOD_MAY_CONT && (ret->decision == DECISION_UNCOND_SUCC || ret->decision == DECISION_COND_SUCC)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " @@ -1808,8 +1456,9 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, id = eap_get_id(reqData); if (flags & EAP_TLS_FLAGS_START) { - if (eap_ttls_process_start(sm, data, flags, ret) < 0) - return NULL; + wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own " + "ver=%d)", flags & EAP_TLS_VERSION_MASK, + data->ttls_version); /* RFC 5281, Ch. 9.2: * "This packet MAY contain additional information in the form @@ -1817,13 +1466,6 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, * For now, ignore any potential extra data. */ left = 0; - } else if (!data->ssl_initialized) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not " - "include Start flag"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - return NULL; } resp = NULL; diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c index 1e169a0..acd7611 100644 --- a/src/eap_peer/ikev2.c +++ b/src/eap_peer/ikev2.c @@ -425,7 +425,7 @@ static int ikev2_process_kei(struct ikev2_responder_data *data, } /* RFC 4306, Section 3.4: - * The length of DH public value MUST be equal to the lenght of the + * The length of DH public value MUST be equal to the length of the * prime modulus. */ if (kei_len - 4 != data->dh->prime_len) { diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h index e1f500a..d5f8f1d 100644 --- a/src/eap_server/eap.h +++ b/src/eap_server/eap.h @@ -22,8 +22,6 @@ struct eap_sm; -#define EAP_MAX_METHODS 8 - #define EAP_TTLS_AUTH_PAP 1 #define EAP_TTLS_AUTH_CHAP 2 #define EAP_TTLS_AUTH_MSCHAP 4 diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h index 3cba5aa..f48cf71 100644 --- a/src/eap_server/eap_i.h +++ b/src/eap_server/eap_i.h @@ -119,7 +119,7 @@ struct eap_sm { /* Full authenticator state machine local variables */ - /* Long-term (maintained betwen packets) */ + /* Long-term (maintained between packets) */ EapType currentMethod; int currentId; enum { diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c index 0f0da29..7a5beb6 100644 --- a/src/eap_server/eap_server.c +++ b/src/eap_server/eap_server.c @@ -136,6 +136,14 @@ SM_STATE(EAP, INITIALIZE) { SM_ENTRY(EAP, INITIALIZE); + if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) { + /* + * Need to allow internal Identity method to be used instead + * of passthrough at the beginning of reauthentication. + */ + eap_server_clear_identity(sm); + } + sm->currentId = -1; sm->eap_if.eapSuccess = FALSE; sm->eap_if.eapFail = FALSE; @@ -1028,9 +1036,12 @@ void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len) not_found: /* not found - remove from the list */ - os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1], - (EAP_MAX_METHODS - i - 1) * - sizeof(sm->user->methods[0])); + if (i + 1 < EAP_MAX_METHODS) { + os_memmove(&sm->user->methods[i], + &sm->user->methods[i + 1], + (EAP_MAX_METHODS - i - 1) * + sizeof(sm->user->methods[0])); + } sm->user->methods[EAP_MAX_METHODS - 1].vendor = EAP_VENDOR_IETF; sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE; diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c index 42cbdce..0f25ffd 100644 --- a/src/eap_server/eap_server_aka.c +++ b/src/eap_server/eap_server_aka.c @@ -133,14 +133,13 @@ static void * eap_aka_prime_init(struct eap_sm *sm) return NULL; data->eap_method = EAP_TYPE_AKA_PRIME; - data->network_name = os_malloc(os_strlen(network_name)); + data->network_name = (u8 *) os_strdup(network_name); if (data->network_name == NULL) { os_free(data); return NULL; } data->network_name_len = os_strlen(network_name); - os_memcpy(data->network_name, network_name, data->network_name_len); data->state = IDENTITY; eap_aka_determine_identity(sm, data, 1, 0); diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c index 900a5dd..4d241a4 100644 --- a/src/eap_server/eap_server_methods.c +++ b/src/eap_server/eap_server_methods.c @@ -167,6 +167,8 @@ void eap_server_unregister_methods(void) const char * eap_server_get_name(int vendor, EapType type) { struct eap_method *m; + if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED) + return "expanded"; for (m = eap_methods; m; m = m->next) { if (m->vendor == vendor && m->method == type) return m->name; diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c index 64120a4..f5ee7f4 100644 --- a/src/eap_server/eap_server_mschapv2.c +++ b/src/eap_server/eap_server_mschapv2.c @@ -405,9 +405,12 @@ static void eap_mschapv2_process_response(struct eap_sm *sm, if (sm->user->password_hash) { pw_hash = sm->user->password; } else { - nt_password_hash(sm->user->password, - sm->user->password_len, - pw_hash_buf); + if (nt_password_hash(sm->user->password, + sm->user->password_len, + pw_hash_buf) < 0) { + data->state = FAILURE; + return; + } pw_hash = pw_hash_buf; } generate_authenticator_response_pwhash( diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c index 8a7d626..50e79c0 100644 --- a/src/eap_server/eap_server_peap.c +++ b/src/eap_server/eap_server_peap.c @@ -351,8 +351,12 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) * in the end of the label just before ISK; is that just a typo?) */ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); - peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys", - isk, sizeof(isk), imck, sizeof(imck)); + if (peap_prfplus(data->peap_version, tk, 40, + "Inner Methods Compound Keys", + isk, sizeof(isk), imck, sizeof(imck)) < 0) { + os_free(tk); + return -1; + } wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", imck, sizeof(imck)); @@ -1060,8 +1064,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm, wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted); - hdr = wpabuf_head(in_decrypted); - if (data->peap_version == 0 && data->state != PHASE2_TLV) { const struct eap_hdr *resp; struct eap_hdr *nhdr; @@ -1320,9 +1322,10 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) * termination for this label while the one used for deriving * IPMK|CMK did not use null termination. */ - peap_prfplus(data->peap_version, data->ipmk, 40, - "Session Key Generating Function", - (u8 *) "\00", 1, csk, sizeof(csk)); + if (peap_prfplus(data->peap_version, data->ipmk, 40, + "Session Key Generating Function", + (u8 *) "\00", 1, csk, sizeof(csk)) < 0) + return NULL; wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); eapKeyData = os_malloc(EAP_TLS_KEY_LEN); if (eapKeyData) { diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c index efc7a82..fb299ae 100644 --- a/src/eap_server/eap_server_psk.c +++ b/src/eap_server/eap_server_psk.c @@ -125,8 +125,10 @@ static struct wpabuf * eap_psk_build_3(struct eap_sm *sm, os_memcpy(buf, data->id_s, data->id_s_len); os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); - if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) + if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) { + os_free(buf); goto fail; + } os_free(buf); if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk, diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c index dd2557a..4c6f4d1 100644 --- a/src/eap_server/eap_server_pwd.c +++ b/src/eap_server/eap_server_pwd.c @@ -156,8 +156,8 @@ eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request"); req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, - sizeof(struct eap_pwd_hdr) + - sizeof(struct eap_pwd_id) + data->id_server_len, + 1 + sizeof(struct eap_pwd_id) + + data->id_server_len, EAP_CODE_REQUEST, id); if (req == NULL) { eap_pwd_state(data, FAILURE); @@ -257,8 +257,7 @@ eap_pwd_build_commit_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, - sizeof(struct eap_pwd_hdr) + - (2 * BN_num_bytes(data->grp->prime)) + + 1 + (2 * BN_num_bytes(data->grp->prime)) + BN_num_bytes(data->grp->order), EAP_CODE_REQUEST, id); if (req == NULL) @@ -289,6 +288,7 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) HMAC_CTX ctx; u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr; u16 grp; + int offset; wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request"); @@ -313,7 +313,8 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) * First is k */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->k, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); + BN_bn2bin(data->k, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* server element: x, y */ @@ -326,15 +327,19 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) } os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(x, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(y, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* server scalar */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->my_scalar, cruft); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->my_scalar); + BN_bn2bin(data->my_scalar, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); /* peer element: x, y */ @@ -347,15 +352,19 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) } os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(x, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(y, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* peer scalar */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->peer_scalar, cruft); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->peer_scalar); + BN_bn2bin(data->peer_scalar, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); /* ciphersuite */ @@ -375,7 +384,7 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) os_memcpy(data->my_confirm, conf, SHA256_DIGEST_LENGTH); req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, - sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH, + 1 + SHA256_DIGEST_LENGTH, EAP_CODE_REQUEST, id); if (req == NULL) goto fin; @@ -624,6 +633,7 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, u32 cs; u16 grp; u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr; + int offset; /* build up the ciphersuite: group | random_function | prf */ grp = htons(data->group_num); @@ -649,7 +659,8 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, /* k */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->k, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); + BN_bn2bin(data->k, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* peer element: x, y */ @@ -661,15 +672,19 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, goto fin; } os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(x, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(y, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* peer scalar */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->peer_scalar, cruft); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->peer_scalar); + BN_bn2bin(data->peer_scalar, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); /* server element: x, y */ @@ -682,15 +697,19 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, } os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(x, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(y, cruft); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); /* server scalar */ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - BN_bn2bin(data->my_scalar, cruft); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->my_scalar); + BN_bn2bin(data->my_scalar, cruft + offset); H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); /* ciphersuite */ diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c index e149ee3..0bb9d14 100644 --- a/src/eap_server/eap_server_tls_common.c +++ b/src/eap_server/eap_server_tls_common.c @@ -94,9 +94,9 @@ u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, os_memcpy(rnd + keys.client_random_len, keys.server_random, keys.server_random_len); - if (tls_prf(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, len)) + if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, + label, rnd, keys.client_random_len + + keys.server_random_len, out, len)) goto fail; os_free(rnd); diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c index 702c50c..398d0f1 100644 --- a/src/eap_server/eap_server_ttls.c +++ b/src/eap_server/eap_server_ttls.c @@ -1,6 +1,6 @@ /* * hostapd / EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -24,16 +24,7 @@ #include "eap_common/eap_ttls.h" -/* Maximum supported TTLS version - * 0 = RFC 5281 - * 1 = draft-funk-eap-ttls-v1-00.txt - */ -#ifndef EAP_TTLS_VERSION -#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */ -#endif /* EAP_TTLS_VERSION */ - - -#define MSCHAPV2_KEY_LEN 16 +#define EAP_TTLS_VERSION 0 static void eap_ttls_reset(struct eap_sm *sm, void *priv); @@ -43,17 +34,15 @@ struct eap_ttls_data { struct eap_ssl_data ssl; enum { START, PHASE1, PHASE2_START, PHASE2_METHOD, - PHASE2_MSCHAPV2_RESP, PHASE_FINISHED, SUCCESS, FAILURE + PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE } state; int ttls_version; - int force_version; const struct eap_method *phase2_method; void *phase2_priv; int mschapv2_resp_ok; u8 mschapv2_auth_response[20]; u8 mschapv2_ident; - int tls_ia_configured; struct wpabuf *pending_phase2_eap_resp; int tnc_started; }; @@ -72,8 +61,6 @@ static const char * eap_ttls_state_txt(int state) return "PHASE2_METHOD"; case PHASE2_MSCHAPV2_RESP: return "PHASE2_MSCHAPV2_RESP"; - case PHASE_FINISHED: - return "PHASE_FINISHED"; case SUCCESS: return "SUCCESS"; case FAILURE: @@ -111,7 +98,8 @@ static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, } avp->avp_code = host_to_be32(avp_code); - avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len)); + avp->avp_length = host_to_be32(((u32) flags << 24) | + ((u32) (hdrlen + len))); return avphdr + hdrlen; } @@ -320,54 +308,8 @@ fail: static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, struct eap_ttls_data *data, size_t len) { - struct tls_keys keys; - u8 *challenge, *rnd; - - if (data->ttls_version == 0) { - return eap_server_tls_derive_key(sm, &data->ssl, - "ttls challenge", len); - } - - os_memset(&keys, 0, sizeof(keys)); - if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || - keys.client_random == NULL || keys.server_random == NULL || - keys.inner_secret == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " - "client random, or server random to derive " - "implicit challenge"); - return NULL; - } - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - challenge = os_malloc(len); - if (rnd == NULL || challenge == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit " - "challenge derivation"); - os_free(rnd); - os_free(challenge); - return NULL; - } - os_memcpy(rnd, keys.server_random, keys.server_random_len); - os_memcpy(rnd + keys.server_random_len, keys.client_random, - keys.client_random_len); - - if (tls_prf(keys.inner_secret, keys.inner_secret_len, - "inner application challenge", rnd, - keys.client_random_len + keys.server_random_len, - challenge, len)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit " - "challenge"); - os_free(rnd); - os_free(challenge); - return NULL; - } - - os_free(rnd); - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge", - challenge, len); - - return challenge; + return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge", + len); } @@ -379,27 +321,8 @@ static void * eap_ttls_init(struct eap_sm *sm) if (data == NULL) return NULL; data->ttls_version = EAP_TTLS_VERSION; - data->force_version = -1; - if (sm->user && sm->user->force_version >= 0) { - data->force_version = sm->user->force_version; - wpa_printf(MSG_DEBUG, "EAP-TTLS: forcing version %d", - data->force_version); - data->ttls_version = data->force_version; - } data->state = START; - if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) && - data->ttls_version > 0) { - if (data->force_version > 0) { - wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and " - "TLS library does not support TLS/IA.", - data->force_version); - eap_ttls_reset(sm, data); - return NULL; - } - data->ttls_version = 0; - } - if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); eap_ttls_reset(sm, data); @@ -516,14 +439,6 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2( } -static struct wpabuf * eap_ttls_build_phase_finished( - struct eap_sm *sm, struct eap_ttls_data *data, int final) -{ - return tls_connection_ia_send_phase_finished(sm->ssl_ctx, - data->ssl.conn, final); -} - - static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id) { struct eap_ttls_data *data = priv; @@ -559,11 +474,6 @@ static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id) data->ssl.tls_out_pos = 0; data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data); break; - case PHASE_FINISHED: - wpabuf_free(data->ssl.tls_out); - data->ssl.tls_out_pos = 0; - data->ssl.tls_out = eap_ttls_build_phase_finished(sm, data, 1); - break; default: wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", __func__, data->state); @@ -591,37 +501,6 @@ static Boolean eap_ttls_check(struct eap_sm *sm, void *priv, } -static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm, - struct eap_ttls_data *data, - const u8 *key, size_t key_len) -{ - u8 *buf; - size_t buf_len; - int ret; - - if (key) { - buf_len = 2 + key_len; - buf = os_malloc(buf_len); - if (buf == NULL) - return -1; - WPA_PUT_BE16(buf, key_len); - os_memcpy(buf + 2, key, key_len); - } else { - buf = NULL; - buf_len = 0; - } - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner " - "secret permutation", buf, buf_len); - ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx, - data->ssl.conn, - buf, buf_len); - os_free(buf); - - return ret; -} - - static void eap_ttls_process_phase2_pap(struct eap_sm *sm, struct eap_ttls_data *data, const u8 *user_password, @@ -644,8 +523,7 @@ static void eap_ttls_process_phase2_pap(struct eap_sm *sm, } wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password"); - eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : - SUCCESS); + eap_ttls_state(data, SUCCESS); } @@ -701,8 +579,7 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm, if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password"); - eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : - SUCCESS); + eap_ttls_state(data, SUCCESS); } else { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password"); eap_ttls_state(data, FAILURE); @@ -762,8 +639,7 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm, if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response"); - eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : - SUCCESS); + eap_ttls_state(data, SUCCESS); } else { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response"); wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received", @@ -863,30 +739,6 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct " "NT-Response"); data->mschapv2_resp_ok = 1; - if (data->ttls_version > 0) { - const u8 *pw_hash; - u8 pw_hash_buf[16], pw_hash_hash[16], master_key[16]; - u8 session_key[2 * MSCHAPV2_KEY_LEN]; - - if (sm->user->password_hash) - pw_hash = sm->user->password; - else { - nt_password_hash(sm->user->password, - sm->user->password_len, - pw_hash_buf); - pw_hash = pw_hash_buf; - } - hash_nt_password_hash(pw_hash, pw_hash_hash); - get_master_key(pw_hash_hash, nt_response, master_key); - get_asymetric_start_key(master_key, session_key, - MSCHAPV2_KEY_LEN, 0, 0); - get_asymetric_start_key(master_key, - session_key + MSCHAPV2_KEY_LEN, - MSCHAPV2_KEY_LEN, 1, 0); - eap_ttls_ia_permute_inner_secret(sm, data, - session_key, - sizeof(session_key)); - } if (sm->user->password_hash) { generate_authenticator_response_pwhash( @@ -1030,17 +882,7 @@ static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm, } break; case PHASE2_METHOD: - if (data->ttls_version > 0) { - if (m->getKey) { - u8 *key; - size_t key_len; - key = m->getKey(sm, priv, &key_len); - eap_ttls_ia_permute_inner_secret(sm, data, - key, key_len); - } - eap_ttls_state(data, PHASE_FINISHED); - } else - eap_ttls_state(data, SUCCESS); + eap_ttls_state(data, SUCCESS); break; case FAILURE: break; @@ -1130,23 +972,6 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, return; } - if (data->state == PHASE_FINISHED) { - if (wpabuf_len(in_decrypted) == 0 && - tls_connection_ia_final_phase_finished(sm->ssl_ctx, - data->ssl.conn)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished " - "received"); - eap_ttls_state(data, SUCCESS); - } else { - wpa_printf(MSG_INFO, "EAP-TTLS: Did not receive valid " - "FinalPhaseFinished"); - eap_ttls_state(data, FAILURE); - } - - wpabuf_free(in_decrypted); - return; - } - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP", in_decrypted); @@ -1245,15 +1070,6 @@ static int eap_ttls_process_version(struct eap_sm *sm, void *priv, data->ttls_version = peer_version; } - if (data->ttls_version > 0 && !data->tls_ia_configured) { - if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable " - "TLS/IA"); - return -1; - } - data->tls_ia_configured = 1; - } - return 0; } @@ -1270,7 +1086,6 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv, break; case PHASE2_START: case PHASE2_METHOD: - case PHASE_FINISHED: eap_ttls_process_phase2(sm, data, data->ssl.tls_in); eap_ttls_start_tnc(sm, data); break; @@ -1279,8 +1094,7 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv, 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " "acknowledged response"); - eap_ttls_state(data, data->ttls_version > 0 ? - PHASE_FINISHED : SUCCESS); + eap_ttls_state(data, SUCCESS); } else if (!data->mschapv2_resp_ok) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " "acknowledged error"); @@ -1321,54 +1135,6 @@ static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv) } -static u8 * eap_ttls_v1_derive_key(struct eap_sm *sm, - struct eap_ttls_data *data) -{ - struct tls_keys keys; - u8 *rnd, *key; - - os_memset(&keys, 0, sizeof(keys)); - if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || - keys.client_random == NULL || keys.server_random == NULL || - keys.inner_secret == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " - "client random, or server random to derive keying " - "material"); - return NULL; - } - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - key = os_malloc(EAP_TLS_KEY_LEN); - if (rnd == NULL || key == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation"); - os_free(rnd); - os_free(key); - return NULL; - } - os_memcpy(rnd, keys.client_random, keys.client_random_len); - os_memcpy(rnd + keys.client_random_len, keys.server_random, - keys.server_random_len); - - if (tls_prf(keys.inner_secret, keys.inner_secret_len, - "ttls v1 keying material", rnd, keys.client_random_len + - keys.server_random_len, key, EAP_TLS_KEY_LEN)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); - os_free(rnd); - os_free(key); - return NULL; - } - - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random", - rnd, keys.client_random_len + keys.server_random_len); - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret", - keys.inner_secret, keys.inner_secret_len); - - os_free(rnd); - - return key; -} - - static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_ttls_data *data = priv; @@ -1377,14 +1143,9 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) if (data->state != SUCCESS) return NULL; - if (data->ttls_version == 0) { - eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, - "ttls keying material", - EAP_TLS_KEY_LEN); - } else { - eapKeyData = eap_ttls_v1_derive_key(sm, data); - } - + eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, + "ttls keying material", + EAP_TLS_KEY_LEN); if (eapKeyData) { *len = EAP_TLS_KEY_LEN; wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", diff --git a/src/eap_server/ikev2.c b/src/eap_server/ikev2.c index 9624d53..f5bbb14 100644 --- a/src/eap_server/ikev2.c +++ b/src/eap_server/ikev2.c @@ -404,7 +404,7 @@ static int ikev2_process_ker(struct ikev2_initiator_data *data, } /* RFC 4306, Section 3.4: - * The length of DH public value MUST be equal to the lenght of the + * The length of DH public value MUST be equal to the length of the * prime modulus. */ if (ker_len - 4 != data->dh->prime_len) { diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c index 4aa71ad..e600954 100644 --- a/src/eapol_auth/eapol_auth_sm.c +++ b/src/eapol_auth/eapol_auth_sm.c @@ -1017,7 +1017,7 @@ static struct eapol_callbacks eapol_cb = int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx) { - if (sm == NULL || ctx != sm->eap) + if (sm == NULL || ctx == NULL || ctx != sm->eap) return -1; eap_sm_pending_cb(sm->eap); diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index bb6cff6..ffc6619 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -561,7 +561,7 @@ SM_STEP(SUPP_BE) * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL * and SUCCESS based on eapFail and eapSuccess, respectively. * However, IEEE Std 802.1X-2004 is also specifying that - * eapNoResp should be set in conjuction with eapSuccess and + * eapNoResp should be set in conjunction with eapSuccess and * eapFail which would mean that more than one of the * transitions here would be activated at the same time. * Skipping RESPONSE and/or RECEIVE states in these cases can @@ -1813,7 +1813,7 @@ static void eapol_sm_notify_pending(void *ctx) #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -static void eapol_sm_eap_param_needed(void *ctx, const char *field, +static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field, const char *txt) { struct eapol_sm *sm = ctx; @@ -1883,6 +1883,7 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) conf.pkcs11_engine_path = ctx->pkcs11_engine_path; conf.pkcs11_module_path = ctx->pkcs11_module_path; conf.wps = ctx->wps; + conf.cert_in_cb = ctx->cert_in_cb; sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf); if (sm->eap == NULL) { diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index 3ea7e79..bcb00b5 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -208,10 +208,10 @@ struct eapol_ctx { /** * eap_param_needed - Notify that EAP parameter is needed * @ctx: Callback context (ctx) - * @field: Field name (e.g., "IDENTITY") + * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY) * @txt: User readable text describing the required parameter */ - void (*eap_param_needed)(void *ctx, const char *field, + void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field, const char *txt); /** @@ -231,6 +231,11 @@ struct eapol_ctx { */ void (*cert_cb)(void *ctx, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert); + + /** + * cert_in_cb - Include server certificates in callback + */ + int cert_in_cb; }; diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index bef3926..8c768f6 100644..100755 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -17,6 +17,9 @@ #include "common.h" #include "eloop.h" #include "common/ieee802_11_defs.h" +#ifdef ANDROID_P2P +#include "common/wpa_ctrl.h" +#endif #include "common/ieee802_11_common.h" #include "wps/wps_i.h" #include "p2p_i.h" @@ -106,12 +109,42 @@ static const char * p2p_state_txt(int state) return "INVITE"; case P2P_INVITE_LISTEN: return "INVITE_LISTEN"; + case P2P_SEARCH_WHEN_READY: + return "SEARCH_WHEN_READY"; default: return "?"; } } +u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr) +{ + struct p2p_device *dev = NULL; + + if (!addr || !p2p) + return 0; + + dev = p2p_get_device(p2p, addr); + if (dev) + return dev->wps_prov_info; + else + return 0; +} + + +void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr) +{ + struct p2p_device *dev = NULL; + + if (!iface_addr || !p2p) + return; + + dev = p2p_get_device_interface(p2p, iface_addr); + if (dev) + dev->wps_prov_info = 0; +} + + void p2p_set_state(struct p2p_data *p2p, int new_state) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s", @@ -144,6 +177,8 @@ void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer, struct p2p_go_neg_results res; p2p_clear_timeout(p2p); p2p_set_state(p2p, P2P_IDLE); + if (p2p->go_neg_peer) + p2p->go_neg_peer->wps_method = WPS_NOT_READY; p2p->go_neg_peer = NULL; os_memset(&res, 0, sizeof(res)); @@ -219,6 +254,12 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout) p2p->pending_listen_usec = (timeout % 1000) * 1000; if (p2p->p2p_scan_running) { + if (p2p->start_after_scan == P2P_AFTER_SCAN_NOTHING) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, + "P2P: p2p_scan running - connect is already " + "pending - skip listen"); + return 0; + } wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan running - delay start of listen state"); p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN; @@ -363,7 +404,7 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr, * group, the information will be restored in the loop following this. */ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - if (os_memcpy(dev->member_in_go_iface, go_interface_addr, + if (os_memcmp(dev->member_in_go_iface, go_interface_addr, ETH_ALEN) == 0) { os_memset(dev->member_in_go_iface, 0, ETH_ALEN); os_memset(dev->member_in_go_dev, 0, ETH_ALEN); @@ -372,6 +413,9 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr, for (c = 0; c < info.num_clients; c++) { struct p2p_client_info *cli = &info.client[c]; + if (os_memcmp(cli->p2p_device_addr, p2p->cfg->dev_addr, + ETH_ALEN) == 0) + continue; /* ignore our own entry */ dev = p2p_get_device(p2p, cli->p2p_device_addr); if (dev) { /* @@ -574,11 +618,6 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level, freq, msg.ds_params ? *msg.ds_params : -1); } dev->listen_freq = freq; -#ifdef ANDROID_BRCM_P2P_PATCH - if(msg.group_info) - dev->go_state = REMOTE_GO; -#endif - if (msg.group_info) dev->oper_freq = freq; dev->info.level = level; @@ -631,9 +670,10 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev) int i; if (p2p->go_neg_peer == dev) { -#ifdef ANDROID_BRCM_P2P_PATCH + /* + * If GO Negotiation is in progress, report that it has failed. + */ p2p_go_neg_failed(p2p, dev, -1); -#endif p2p->go_neg_peer = NULL; } if (p2p->invite_peer == dev) @@ -787,19 +827,18 @@ static int p2p_run_after_scan(struct p2p_data *p2p) enum p2p_after_scan op; if (p2p->after_scan_tx) { - int ret; /* TODO: schedule p2p_run_after_scan to be called from TX * status callback(?) */ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send pending " "Action frame at p2p_scan completion"); - ret = p2p->cfg->send_action(p2p->cfg->cb_ctx, - p2p->after_scan_tx->freq, - p2p->after_scan_tx->dst, - p2p->after_scan_tx->src, - p2p->after_scan_tx->bssid, - (u8 *) (p2p->after_scan_tx + 1), - p2p->after_scan_tx->len, - p2p->after_scan_tx->wait_time); + p2p->cfg->send_action(p2p->cfg->cb_ctx, + p2p->after_scan_tx->freq, + p2p->after_scan_tx->dst, + p2p->after_scan_tx->src, + p2p->after_scan_tx->bssid, + (u8 *) (p2p->after_scan_tx + 1), + p2p->after_scan_tx->len, + p2p->after_scan_tx->wait_time); os_free(p2p->after_scan_tx); p2p->after_scan_tx = NULL; return 1; @@ -888,6 +927,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, p2p_device_clear_reported(p2p); p2p_set_state(p2p, P2P_SEARCH); eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); + p2p->last_p2p_find_timeout = timeout; if (timeout) eloop_register_timeout(timeout, 0, p2p_find_timeout, p2p, NULL); @@ -913,21 +953,47 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout, p2p, NULL); + } else if (res == 1) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start " + "p2p_scan at this point - will try again after " + "previous scan completes"); + res = 0; + p2p_set_state(p2p, P2P_SEARCH_WHEN_READY); + eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); } else { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start " "p2p_scan"); + p2p_set_state(p2p, P2P_IDLE); + eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); } return res; } +int p2p_other_scan_completed(struct p2p_data *p2p) +{ + if (p2p->state != P2P_SEARCH_WHEN_READY) + return 0; + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find " + "now that previous scan was completed"); + if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type, + p2p->num_req_dev_types, p2p->req_dev_types) < 0) + return 0; + return 1; +} + + void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find"); eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); p2p_clear_timeout(p2p); p2p_set_state(p2p, P2P_IDLE); +#ifdef ANDROID_P2P + wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED); +#endif + p2p_free_req_dev_types(p2p); p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; p2p->go_neg_peer = NULL; @@ -938,6 +1004,16 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq) "since we are on correct channel for response"); return; } + if (p2p->drv_in_listen) { + /* + * The driver may not deliver callback to p2p_listen_end() + * when the operation gets canceled, so clear the internal + * variable that is tracking driver state. + */ + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear " + "drv_in_listen (%d)", p2p->drv_in_listen); + p2p->drv_in_listen = 0; + } p2p->cfg->stop_listen(p2p->cfg->cb_ctx); } @@ -1027,6 +1103,26 @@ static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq) } +static void p2p_set_dev_persistent(struct p2p_device *dev, + int persistent_group) +{ + switch (persistent_group) { + case 0: + dev->flags &= ~(P2P_DEV_PREFER_PERSISTENT_GROUP | + P2P_DEV_PREFER_PERSISTENT_RECONN); + break; + case 1: + dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP; + dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_RECONN; + break; + case 2: + dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP | + P2P_DEV_PREFER_PERSISTENT_RECONN; + break; + } +} + + int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, @@ -1044,6 +1140,7 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, if (p2p_prepare_channel(p2p, force_freq) < 0) return -1; + p2p->ssid_set = 0; dev = p2p_get_device(p2p, peer_addr); if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, @@ -1083,10 +1180,7 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, dev->connect_reqs = 0; dev->go_neg_req_sent = 0; dev->go_state = UNKNOWN_GO; - if (persistent_group) - dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP; - else - dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP; + p2p_set_dev_persistent(dev, persistent_group); p2p->go_intent = go_intent; os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); @@ -1156,10 +1250,7 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, dev->flags &= ~P2P_DEV_USER_REJECTED; dev->go_neg_req_sent = 0; dev->go_state = UNKNOWN_GO; - if (persistent_group) - dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP; - else - dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP; + p2p_set_dev_persistent(dev, persistent_group); p2p->go_intent = go_intent; os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); @@ -1270,8 +1361,12 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN); os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN); res.wps_method = peer->wps_method; - if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) - res.persistent_group = 1; + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN) + res.persistent_group = 2; + else + res.persistent_group = 1; + } if (go) { /* Setup AP mode for WPS provisioning */ @@ -1311,6 +1406,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout; p2p_clear_timeout(p2p); + p2p->ssid_set = 0; peer->go_neg_req_sent = 0; peer->wps_method = WPS_NOT_READY; @@ -1367,9 +1463,9 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa, } -void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da, const u8 *sa, - const u8 *bssid, const u8 *data, size_t len, - int freq) +static void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da, + const u8 *sa, const u8 *bssid, const u8 *data, + size_t len, int freq) { if (len < 1) return; @@ -1514,6 +1610,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr, if (dev) { if (dev->country[0] == 0 && msg.listen_channel) os_memcpy(dev->country, msg.listen_channel, 3); + os_get_time(&dev->last_seen); p2p_parse_free(&msg); return; /* already known */ } @@ -1653,13 +1750,47 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p) } -static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie, +static int is_11b(u8 rate) +{ + return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; +} + + +static int supp_rates_11b_only(struct ieee802_11_elems *elems) +{ + int num_11b = 0, num_others = 0; + int i; + + if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL) + return 0; + + for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) { + if (is_11b(elems->supp_rates[i])) + num_11b++; + else + num_others++; + } + + for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len; + i++) { + if (is_11b(elems->ext_supp_rates[i])) + num_11b++; + else + num_others++; + } + + return num_11b > 0 && num_others == 0; +} + + +static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, + const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len) { struct ieee802_11_elems elems; struct wpabuf *buf; struct ieee80211_mgmt *resp; - struct wpabuf *wps; + struct p2p_message msg; struct wpabuf *ies; if (!p2p->in_listen || !p2p->drv_in_listen) { @@ -1678,6 +1809,18 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie, return; } + if (dst && !is_broadcast_ether_addr(dst) && + os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) { + /* Not sent to the broadcast address or our P2P Device Address + */ + return; + } + + if (bssid && !is_broadcast_ether_addr(bssid)) { + /* Not sent to the Wildcard BSSID */ + return; + } + if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN || os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) != 0) { @@ -1685,14 +1828,32 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie, return; } + if (supp_rates_11b_only(&elems)) { + /* Indicates support for 11b rates only */ + return; + } + + os_memset(&msg, 0, sizeof(msg)); + if (p2p_parse_ies(ie, ie_len, &msg) < 0) { + /* Could not parse P2P attributes */ + return; + } + + if (msg.device_id && + os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) { + /* Device ID did not match */ + p2p_parse_free(&msg); + return; + } + /* Check Requested Device Type match */ - wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); - if (wps && !p2p_match_dev_type(p2p, wps)) { - wpabuf_free(wps); + if (msg.wps_attributes && + !p2p_match_dev_type(p2p, msg.wps_attributes)) { /* No match with Requested Device Type */ + p2p_parse_free(&msg); return; } - wpabuf_free(wps); + p2p_parse_free(&msg); if (!p2p->cfg->send_probe_resp) return; /* Response generated elsewhere */ @@ -1759,12 +1920,12 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie, } -int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie, - size_t ie_len) +int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst, + const u8 *bssid, const u8 *ie, size_t ie_len) { p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len); - p2p_reply_probe(p2p, addr, ie, ie_len); + p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len); if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) && p2p->go_neg_peer && @@ -2221,11 +2382,11 @@ void p2p_continue_find(struct p2p_data *p2p) } else if (dev->req_config_methods && !(dev->flags & P2P_DEV_PD_FOR_JOIN)) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send " - "pending Provisioning Discovery Request to " + "pending Provision Discovery Request to " MACSTR " (config methods 0x%x)", MAC2STR(dev->info.p2p_device_addr), dev->req_config_methods); - if (p2p_send_prov_disc_req(p2p, dev, 0) == 0) + if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0) return; } } @@ -2267,7 +2428,7 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success) * p2p_retry_pd - Retry any pending provision disc requests in IDLE state * @p2p: P2P module context from p2p_init() */ -void p2p_retry_pd(struct p2p_data *p2p) +static void p2p_retry_pd(struct p2p_data *p2p) { struct p2p_device *dev; @@ -2290,11 +2451,11 @@ void p2p_retry_pd(struct p2p_data *p2p) continue; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send " - "pending Provisioning Discovery Request to " + "pending Provision Discovery Request to " MACSTR " (config methods 0x%x)", MAC2STR(dev->info.p2p_device_addr), dev->req_config_methods); - p2p_send_prov_disc_req(p2p, dev, 0); + p2p_send_prov_disc_req(p2p, dev, 0, 0); return; } } @@ -2395,6 +2556,12 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies) } +size_t p2p_scan_ie_buf_len(struct p2p_data *p2p) +{ + return 100; +} + + int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end) { return p2p_attr_text(p2p_ie, buf, end); @@ -2674,15 +2841,7 @@ static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p) * state once per second to give other uses a chance to use the radio. */ p2p_set_state(p2p, P2P_WAIT_PEER_IDLE); -#ifdef ANDROID_BRCM_P2P_PATCH - /* - * We need to be back in Listen state soon enough so that we don't miss - * the GO Nego req from the peer. - */ - p2p_set_timeout(p2p, 0, 0); -#else - p2p_set_timeout(p2p, 1, 0); -#endif + p2p_set_timeout(p2p, 0, 500000); } @@ -2862,6 +3021,8 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx) case P2P_INVITE_LISTEN: p2p_timeout_invite_listen(p2p); break; + case P2P_SEARCH_WHEN_READY: + break; } } @@ -2884,13 +3045,11 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr) } -static const char * p2p_wps_method_text(enum p2p_wps_method method) +const char * p2p_wps_method_text(enum p2p_wps_method method) { switch (method) { case WPS_NOT_READY: return "not-ready"; - case WPS_PIN_LABEL: - return "Label"; case WPS_PIN_DISPLAY: return "Display"; case WPS_PIN_KEYPAD: @@ -2918,14 +3077,10 @@ static const char * p2p_go_state_text(enum p2p_go_state go_state) } -int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next, - char *buf, size_t buflen) +const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p, + const u8 *addr, int next) { struct p2p_device *dev; - int res; - char *pos, *end; - struct os_time now; - char devtype[WPS_DEV_TYPE_BUFSIZE]; if (addr) dev = p2p_get_device(p2p, addr); @@ -2939,35 +3094,37 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next, } if (dev == NULL) + return NULL; + + return &dev->info; +} + + +int p2p_get_peer_info_txt(const struct p2p_peer_info *info, + char *buf, size_t buflen) +{ + struct p2p_device *dev; + int res; + char *pos, *end; + struct os_time now; + + if (info == NULL) return -1; + dev = (struct p2p_device *) (((u8 *) info) - + offsetof(struct p2p_device, info)); + pos = buf; end = buf + buflen; - res = os_snprintf(pos, end - pos, MACSTR "\n", - MAC2STR(dev->info.p2p_device_addr)); - if (res < 0 || res >= end - pos) - return pos - buf; - pos += res; - os_get_time(&now); res = os_snprintf(pos, end - pos, "age=%d\n" "listen_freq=%d\n" - "level=%d\n" "wps_method=%s\n" "interface_addr=" MACSTR "\n" "member_in_go_dev=" MACSTR "\n" "member_in_go_iface=" MACSTR "\n" - "pri_dev_type=%s\n" - "device_name=%s\n" - "manufacturer=%s\n" - "model_name=%s\n" - "model_number=%s\n" - "serial_number=%s\n" - "config_methods=0x%x\n" - "dev_capab=0x%x\n" - "group_capab=0x%x\n" "go_neg_req_sent=%d\n" "go_state=%s\n" "dialog_token=%u\n" @@ -2981,21 +3138,10 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next, "invitation_reqs=%u\n", (int) (now.sec - dev->last_seen.sec), dev->listen_freq, - dev->info.level, p2p_wps_method_text(dev->wps_method), MAC2STR(dev->interface_addr), MAC2STR(dev->member_in_go_dev), MAC2STR(dev->member_in_go_iface), - wps_dev_type_bin2str(dev->info.pri_dev_type, - devtype, sizeof(devtype)), - dev->info.device_name, - dev->info.manufacturer, - dev->info.model_name, - dev->info.model_number, - dev->info.serial_number, - dev->info.config_methods, - dev->info.dev_capab, - dev->info.group_capab, dev->go_neg_req_sent, p2p_go_state_text(dev->go_state), dev->dialog_token, @@ -3064,6 +3210,12 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next, } +int p2p_peer_known(struct p2p_data *p2p, const u8 *addr) +{ + return p2p_get_device(p2p, addr) != NULL; +} + + void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled) { if (enabled) { @@ -3624,3 +3776,20 @@ p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next) return &dev->info; } + +#ifdef ANDROID_P2P +int p2p_search_in_progress(struct p2p_data *p2p) +{ + if (p2p == NULL) + return 0; + + return p2p->state == P2P_SEARCH; +} +#endif + +int p2p_in_progress(struct p2p_data *p2p) +{ + if (p2p == NULL) + return 0; + return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING; +} diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 72c90b1..05b4a16 100644..100755 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -56,7 +56,7 @@ struct p2p_channels { }; enum p2p_wps_method { - WPS_NOT_READY, WPS_PIN_LABEL, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC + WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC }; /** @@ -120,6 +120,9 @@ struct p2p_go_neg_results { /** * persistent_group - Whether the group should be made persistent + * 0 = not persistent + * 1 = persistent group without persistent reconnect + * 2 = persistent group with persistent reconnect */ int persistent_group; @@ -292,17 +295,6 @@ struct p2p_config { */ u8 dev_addr[ETH_ALEN]; -#ifdef ANDROID_BRCM_P2P_PATCH - /** - * p2p_dev_addr - P2P Device Address - * - * Holds the p2p device address. If the driver uses primary mac address - * for p2p operations, then this will hold the same value as that of - * dev_addr. - */ - u8 p2p_dev_addr[ETH_ALEN]; -#endif - /** * dev_name - Device Name */ @@ -602,6 +594,8 @@ struct p2p_config { * @supp_config_methods: Supported configuration Methods * @dev_capab: Device Capabilities * @group_capab: Group Capabilities + * @group_id: P2P Group ID (or %NULL if not included) + * @group_id_len: Length of P2P Group ID * * This callback is used to indicate reception of a Provision Discovery * Request frame that the P2P module accepted. @@ -609,7 +603,8 @@ struct p2p_config { void (*prov_disc_req)(void *ctx, const u8 *peer, u16 config_methods, const u8 *dev_addr, const u8 *pri_dev_type, const char *dev_name, u16 supp_config_methods, - u8 dev_capab, u8 group_capab); + u8 dev_capab, u8 group_capab, + const u8 *group_id, size_t group_id_len); /** * prov_disc_resp - Callback on Provisiong Discovery Response @@ -857,7 +852,9 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout); * @go_intent: Local GO intent value (1..15) * @own_interface_addr: Intended interface address to use with the group * @force_freq: The only allowed channel frequency in MHz or 0 - * @persistent_group: Whether to create a persistent group + * @persistent_group: Whether to create a persistent group (0 = no, 1 = + * persistent group without persistent reconnect, 2 = persistent group with + * persistent reconnect) * Returns: 0 on success, -1 on failure */ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, @@ -873,7 +870,9 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, * @go_intent: Local GO intent value (1..15) * @own_interface_addr: Intended interface address to use with the group * @force_freq: The only allowed channel frequency in MHz or 0 - * @persistent_group: Whether to create a persistent group + * @persistent_group: Whether to create a persistent group (0 = no, 1 = + * persistent group without persistent reconnect, 2 = persistent group with + * persistent reconnect) * Returns: 0 on success, -1 on failure * * This is like p2p_connect(), but the actual group negotiation is not @@ -898,6 +897,7 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr); * @peer_addr: MAC address of the peer P2P client * @config_methods: WPS Config Methods value (only one bit set) * @join: Whether this is used by a client joining an active group + * @force_freq: Forced TX frequency for the frame (mainly for the join case) * Returns: 0 on success, -1 on failure * * This function can be used to request a discovered P2P peer to display a PIN @@ -909,7 +909,7 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr); * indicated with the p2p_config::prov_disc_resp() callback. */ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, - u16 config_methods, int join); + u16 config_methods, int join, int force_freq); /** * p2p_sd_request - Schedule a service discovery query @@ -1039,6 +1039,28 @@ void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr); */ void p2p_group_formation_failed(struct p2p_data *p2p); +/** + * p2p_get_provisioning_info - Get any stored provisioning info + * @p2p: P2P module context from p2p_init() + * @addr: Peer P2P Device Address + * Returns: WPS provisioning information (WPS config method) or 0 if no + * information is available + * + * This function is used to retrieve stored WPS provisioning info for the given + * peer. + */ +u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr); + +/** + * p2p_clear_provisioning_info - Clear any stored provisioning info + * @p2p: P2P module context from p2p_init() + * @iface_addr: Peer P2P Interface Address + * + * This function is used to clear stored WPS provisioning info for the given + * peer. + */ +void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr); + /* Event notifications from lower layer driver operations */ @@ -1046,12 +1068,14 @@ void p2p_group_formation_failed(struct p2p_data *p2p); * p2p_probe_req_rx - Report reception of a Probe Request frame * @p2p: P2P module context from p2p_init() * @addr: Source MAC address + * @dst: Destination MAC address if available or %NULL + * @bssid: BSSID if available or %NULL * @ie: Information elements from the Probe Request frame body * @ie_len: Length of ie buffer in octets * Returns: 0 to indicate the frame was not processed or 1 if it was */ -int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie, - size_t ie_len); +int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst, + const u8 *bssid, const u8 *ie, size_t ie_len); /** * p2p_rx_action - Report received Action frame @@ -1173,6 +1197,9 @@ struct p2p_group; struct p2p_group_config { /** * persistent_group - Whether the group is persistent + * 0 = not a persistent group + * 1 = persistent group without persistent reconnect + * 2 = persistent group with persistent reconnect */ int persistent_group; @@ -1244,16 +1271,6 @@ void p2p_group_deinit(struct p2p_group *group); */ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr, const u8 *ie, size_t len); -#ifdef ANDROID_BRCM_P2P_PATCH -/** - * p2p_group_get_dev_addr - Retreive the device address of an assocated P2P - * client. - * @group: P2P group context from p2p_group_init() - * @addr: Interface address of the P2P client - * Returns: P2P dev_addr on success, NULL on failure - */ -u8 *p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr); -#endif /*ANDROID_BRCM_P2P_PATCH */ /** * p2p_group_assoc_resp_ie - Build P2P IE for (re)association response @@ -1363,6 +1380,13 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies); /** + * p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie + * @p2p: P2P module context from p2p_init() + * Returns: Number of octets that p2p_scan_ie() may add to the buffer + */ +size_t p2p_scan_ie_buf_len(struct p2p_data *p2p); + +/** * p2p_go_params - Generate random P2P group parameters * @p2p: P2P module context from p2p_init() * @params: Buffer for parameters @@ -1392,16 +1416,36 @@ int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie); const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie); /** - * p2p_get_peer_info - Get P2P peer information in text format + * p2p_get_peer_info - Get P2P peer information * @p2p: P2P module context from p2p_init() * @addr: P2P Device Address of the peer or %NULL to indicate the first peer * @next: Whether to select the peer entry following the one indicated by addr + * Returns: Pointer to peer info or %NULL if not found + */ +const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p, + const u8 *addr, int next); + +/** + * p2p_get_peer_info_txt - Get internal P2P peer information in text format + * @info: Pointer to P2P peer info from p2p_get_peer_info() * @buf: Buffer for returning text * @buflen: Maximum buffer length * Returns: Number of octets written to the buffer or -1 on failure + * + * Note: This information is internal to the P2P module and subject to change. + * As such, this should not really be used by external programs for purposes + * other than debugging. + */ +int p2p_get_peer_info_txt(const struct p2p_peer_info *info, + char *buf, size_t buflen); + +/** + * p2p_peer_known - Check whether P2P peer is known + * @p2p: P2P module context from p2p_init() + * @addr: P2P Device Address of the peer + * Returns: 1 if the specified device is in the P2P peer table or 0 if not */ -int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next, - char *buf, size_t buflen); +int p2p_peer_known(struct p2p_data *p2p, const u8 *addr); /** * p2p_set_client_discoverability - Set client discoverability capability @@ -1415,7 +1459,7 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next, void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled); /** - * p2p_set_manageD_oper - Set managed P2P Device operations capability + * p2p_set_managed_oper - Set managed P2P Device operations capability * @p2p: P2P module context from p2p_init() * @enabled: Whether managed P2P Device operations will be enabled */ @@ -1490,6 +1534,15 @@ unsigned int p2p_get_group_num_members(struct p2p_group *group); const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next); /** + * 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 + * Returns: P2P Device Address of the client if found or %NULL if no match + * found + */ +const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr); + +/** * p2p_get_peer_found - Get P2P peer info structure of a found peer * @p2p: P2P module context from p2p_init() * @addr: P2P Device Address of the peer or %NULL to indicate the first peer @@ -1528,4 +1581,29 @@ int p2p_add_wps_vendor_extension(struct p2p_data *p2p, int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel, int cfg_op_channel); +/** + * p2p_in_progress - Check whether a P2P operation is progress + * @p2p: P2P module context from p2p_init() + * Returns: 0 if P2P module is idle or 1 if an operation is in progress + */ +int p2p_in_progress(struct p2p_data *p2p); + +#ifdef ANDROID_P2P +/** + * p2p_in_progress - Check whether a P2P SEARCH is in progress + * @p2p: P2P module context from p2p_init() + * Returns: 0 if P2P module is idle or 1 if an operation is in progress + */ +int p2p_search_in_progress(struct p2p_data *p2p); +#endif + +/** + * p2p_other_scan_completed - Notify completion of non-P2P scan + * @p2p: P2P module context from p2p_init() + * Returns: 0 if P2P module is idle or 1 if an operation was started + */ +int p2p_other_scan_completed(struct p2p_data *p2p); + +const char * p2p_wps_method_text(enum p2p_wps_method method); + #endif /* P2P_H */ diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index d59e54b..a82e16d 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -164,27 +164,20 @@ void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p, len = wpabuf_put(buf, 2); /* IE length to be filled */ /* P2P Device address */ -#ifdef ANDROID_BRCM_P2P_PATCH - /* - * P2P_ADDR: Supplicant uses primary mac addr for p2p and hence advertises that. To - * to make it compatible with solution using virtual interface for P2P, a new variable - * is added to hold the actual p2p device address. - */ - wpabuf_put_data(buf, p2p->cfg->p2p_dev_addr, ETH_ALEN); -#else wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); -#endif /* Config Methods */ methods = 0; if (peer && peer->wps_method != WPS_NOT_READY) { if (peer->wps_method == WPS_PBC) methods |= WPS_CONFIG_PUSHBUTTON; - else if (peer->wps_method == WPS_PIN_LABEL) - methods |= WPS_CONFIG_LABEL; else if (peer->wps_method == WPS_PIN_DISPLAY || peer->wps_method == WPS_PIN_KEYPAD) methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; + } else if (p2p->cfg->config_methods) { + methods |= p2p->cfg->config_methods & + (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY | + WPS_CONFIG_KEYPAD); } else { methods |= WPS_CONFIG_PUSHBUTTON; methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index f5937b9..eb85f51 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -107,8 +107,6 @@ static int p2p_peer_channels(struct p2p_data *p2p, struct p2p_device *dev, static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method) { switch (wps_method) { - case WPS_PIN_LABEL: - return DEV_PW_DEFAULT; case WPS_PIN_DISPLAY: return DEV_PW_REGISTRAR_SPECIFIED; case WPS_PIN_KEYPAD: @@ -124,8 +122,6 @@ static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method) static const char * p2p_wps_method_str(enum p2p_wps_method wps_method) { switch (wps_method) { - case WPS_PIN_LABEL: - return "Label"; case WPS_PIN_DISPLAY: return "Display"; case WPS_PIN_KEYPAD: @@ -156,8 +152,11 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, len = p2p_buf_add_ie_hdr(buf); group_capab = 0; - if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN) + group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN; + } if (p2p->cross_connect) group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; if (p2p->cfg->p2p_intra_bss) @@ -246,8 +245,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, p2p_buf_add_status(buf, status); group_capab = 0; if (peer && peer->go_state == LOCAL_GO) { - if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN) + group_capab |= + P2P_GROUP_CAPAB_PERSISTENT_RECONN; + } if (p2p->cross_connect) group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; if (p2p->cfg->p2p_intra_bss) @@ -491,15 +494,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, } if (dev->go_neg_req_sent && -#ifdef ANDROID_BRCM_P2P_PATCH - /* P2P_ADDR: compare against the p2p device address. The own mac - address may not not be the actual p2p device address, if you - are using a virtual interface. - */ - os_memcmp(sa, p2p->cfg->p2p_dev_addr, ETH_ALEN) > 0) { -#else os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) { -#endif wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not reply since peer has higher " "address and GO Neg Request already sent"); @@ -524,18 +519,6 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, } switch (msg.dev_password_id) { - case DEV_PW_DEFAULT: - wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: PIN from peer Label"); - if (dev->wps_method != WPS_PIN_KEYPAD) { - wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: We have wps_method=%s -> " - "incompatible", - p2p_wps_method_str(dev->wps_method)); - status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; - goto fail; - } - break; case DEV_PW_REGISTRAR_SPECIFIED: wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: PIN from peer Display"); @@ -551,8 +534,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, case DEV_PW_USER_SPECIFIED: wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer entered PIN on Keypad"); - if (dev->wps_method != WPS_PIN_LABEL && - dev->wps_method != WPS_PIN_DISPLAY) { + if (dev->wps_method != WPS_PIN_DISPLAY) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: We have wps_method=%s -> " "incompatible", @@ -606,7 +588,10 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, p2p->op_channel)) p2p_reselect_channel(p2p, &intersection); - p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len); + if (!p2p->ssid_set) { + p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len); + p2p->ssid_set = 1; + } } dev->go_state = go ? LOCAL_GO : REMOTE_GO; @@ -695,8 +680,12 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, p2p_buf_add_status(buf, status); group_capab = 0; if (peer->go_state == LOCAL_GO) { - if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN) + group_capab |= + P2P_GROUP_CAPAB_PERSISTENT_RECONN; + } if (p2p->cross_connect) group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; if (p2p->cfg->p2p_intra_bss) @@ -907,18 +896,6 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, dev->oper_freq = 0; switch (msg.dev_password_id) { - case DEV_PW_DEFAULT: - wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: PIN from peer Label"); - if (dev->wps_method != WPS_PIN_KEYPAD) { - wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: We have wps_method=%s -> " - "incompatible", - p2p_wps_method_str(dev->wps_method)); - status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; - goto fail; - } - break; case DEV_PW_REGISTRAR_SPECIFIED: wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: PIN from peer Display"); @@ -934,8 +911,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, case DEV_PW_USER_SPECIFIED: wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer entered PIN on Keypad"); - if (dev->wps_method != WPS_PIN_LABEL && - dev->wps_method != WPS_PIN_DISPLAY) { + if (dev->wps_method != WPS_PIN_DISPLAY) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: We have wps_method=%s -> " "incompatible", @@ -988,7 +964,10 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, p2p->op_channel)) p2p_reselect_channel(p2p, &intersection); - p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len); + if (!p2p->ssid_set) { + p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len); + p2p->ssid_set = 1; + } } p2p_set_state(p2p, P2P_GO_NEG); diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c index 0d05319..59d1507 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -147,8 +147,11 @@ static void p2p_group_add_common_ies(struct p2p_group *group, dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY; dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE; group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; - if (group->cfg->persistent_group) + if (group->cfg->persistent_group) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (group->cfg->persistent_group == 2) + group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN; + } if (group->p2p->cfg->p2p_intra_bss) group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; if (group->group_formation) @@ -183,12 +186,7 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) len = p2p_buf_add_ie_hdr(ie); p2p_group_add_common_ies(group, ie); -#ifdef ANDROID_BRCM_P2P_PATCH - /* P2P_ADDR: Use p2p_dev_addr instead of own mac addr*/ - p2p_buf_add_device_id(ie, group->p2p->cfg->p2p_dev_addr); -#else p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr); -#endif p2p_group_add_noa(ie, group->noa); p2p_buf_update_ie_hdr(ie, len); @@ -315,6 +313,36 @@ static struct wpabuf * p2p_build_client_info(const u8 *addr, } +static int p2p_group_remove_member(struct p2p_group *group, const u8 *addr) +{ + struct p2p_group_member *m, *prev; + + if (group == NULL) + return 0; + + m = group->members; + prev = NULL; + while (m) { + if (os_memcmp(m->addr, addr, ETH_ALEN) == 0) + break; + prev = m; + m = m->next; + } + + if (m == NULL) + return 0; + + if (prev) + prev->next = m->next; + else + group->members = m->next; + p2p_group_free_member(m); + group->num_members--; + + return 1; +} + + int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr, const u8 *ie, size_t len) { @@ -334,6 +362,8 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr, m->dev_addr); } + p2p_group_remove_member(group, addr); + m->next = group->members; group->members = m; group->num_members++; @@ -376,27 +406,7 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr) { - struct p2p_group_member *m, *prev; - - if (group == NULL) - return; - - m = group->members; - prev = NULL; - while (m) { - if (os_memcmp(m->addr, addr, ETH_ALEN) == 0) - break; - prev = m; - m = m->next; - } - - if (m) { - if (prev) - prev->next = m->next; - else - group->members = m->next; - p2p_group_free_member(m); - group->num_members--; + if (p2p_group_remove_member(group, addr)) { wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove " "client " MACSTR " from group; num_members=%u/%u", MAC2STR(addr), group->num_members, @@ -499,11 +509,7 @@ int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa, } else { if (group->noa) { if (wpabuf_size(group->noa) >= noa_len) { - #ifdef ANDROID_BRCM_P2P_PATCH group->noa->used = 0; - #else - group->noa->size = 0; - #endif wpabuf_put_data(group->noa, noa, noa_len); } else { wpabuf_free(group->noa); @@ -551,19 +557,19 @@ static struct p2p_group_member * p2p_group_get_client_iface( return NULL; } -#ifdef ANDROID_BRCM_P2P_PATCH -u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr) + +const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr) { struct p2p_group_member *m; + if (group == NULL) + return NULL; m = p2p_group_get_client_iface(group, addr); - - if (m) + if (m && !is_zero_ether_addr(m->dev_addr)) return m->dev_addr; - else - return NULL; + return NULL; } -#endif /* ANDROID_BRCM_P2P_PATCH */ + static struct wpabuf * p2p_build_go_disc_req(void) { @@ -662,11 +668,11 @@ u8 p2p_group_presence_req(struct p2p_group *group, else wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa, curr_noa_len); -#ifndef ANDROID_BRCM_P2P_PATCH + /* TODO: properly process request and store copy */ - if (curr_noa_len > 0) + if (curr_noa_len > 0 || curr_noa_len == -1) return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; -#endif + return P2P_SC_SUCCESS; } diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index afb891e..0dc33e7 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -18,8 +18,6 @@ #include "utils/list.h" #include "p2p.h" -/* TODO: add removal of expired P2P device entries */ - enum p2p_go_state { UNKNOWN_GO, LOCAL_GO, @@ -69,10 +67,18 @@ struct p2p_device { size_t oper_ssid_len; /** - * req_config_methods - Pending provisioning discovery methods + * req_config_methods - Pending provision discovery methods */ u16 req_config_methods; + /** + * wps_prov_info - Stored provisioning WPS config method + * + * This is used to store pending WPS config method between Provisioning + * Discovery and connection to a running group. + */ + u16 wps_prov_info; + #define P2P_DEV_PROBE_REQ_ONLY BIT(0) #define P2P_DEV_REPORTED BIT(1) #define P2P_DEV_NOT_YET_READY BIT(2) @@ -89,6 +95,7 @@ struct p2p_device { #define P2P_DEV_FORCE_FREQ BIT(13) #define P2P_DEV_PD_FOR_JOIN BIT(14) #define P2P_DEV_REPORTED_ONCE BIT(15) +#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16) unsigned int flags; int status; /* enum p2p_status_code */ @@ -200,6 +207,11 @@ struct p2p_data { * P2P_INVITE_LISTEN - Listen during Invite */ P2P_INVITE_LISTEN, + + /** + * P2P_SEARCH_WHEN_READY - Waiting to start Search + */ + P2P_SEARCH_WHEN_READY, } state; /** @@ -273,6 +285,11 @@ struct p2p_data { size_t ssid_len; /** + * ssid_set - Whether SSID is already set for GO Negotiation + */ + int ssid_set; + + /** * Regulatory class for own operational channel */ u8 op_reg_class; @@ -349,6 +366,7 @@ struct p2p_data { int inv_persistent; enum p2p_discovery_type find_type; + unsigned int last_p2p_find_timeout; u8 last_prog_scan_class; u8 last_prog_scan_chan; int p2p_scan_running; @@ -532,11 +550,6 @@ struct p2p_noa_desc { /* p2p_group.c */ const u8 * p2p_group_get_interface_addr(struct p2p_group *group); - -#ifdef ANDROID_BRCM_P2P_PATCH -void p2p_get_group_noa(struct p2p_group *group, u8 *noa, size_t* noa_len); -#endif - u8 p2p_group_presence_req(struct p2p_group *group, const u8 *client_interface_addr, const u8 *noa, size_t noa_len); @@ -606,7 +619,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len); int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, - int join); + int join, int force_freq); void p2p_reset_pending_pd(struct p2p_data *p2p); /* p2p_invitation.c */ diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index 42015ad..bb2767d 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -55,11 +55,7 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT) dev_addr = peer->info.p2p_device_addr; else -#ifdef ANDROID_BRCM_P2P_PATCH - dev_addr = p2p->cfg->p2p_dev_addr; -#else dev_addr = p2p->cfg->dev_addr; -#endif p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len); p2p_buf_add_device_info(buf, p2p, peer); p2p_buf_update_ie_hdr(buf, len); diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index 32d82f6..1ee59c5 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -112,7 +112,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, MAC2STR(sa), msg.wps_config_methods, rx_freq); dev = p2p_get_device(p2p, sa); - if (dev == NULL || !(dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { + if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision Discovery Request from " "unknown peer " MACSTR, MAC2STR(sa)); @@ -191,8 +191,8 @@ out: msg.device_name, msg.config_methods, msg.capability ? msg.capability[0] : 0, msg.capability ? msg.capability[1] : - 0); - + 0, + msg.group_id, msg.group_id_len); } p2p_parse_free(&msg); } @@ -209,14 +209,14 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, return; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Received Provisioning Discovery Response from " MACSTR + "P2P: Received Provision Discovery Response from " MACSTR " with config methods 0x%x", MAC2STR(sa), msg.wps_config_methods); dev = p2p_get_device(p2p, sa); if (dev == NULL || !dev->req_config_methods) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Ignore Provisioning Discovery Response from " + "P2P: Ignore Provision Discovery Response from " MACSTR " with no pending request", MAC2STR(sa)); p2p_parse_free(&msg); return; @@ -229,7 +229,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, if (dev->dialog_token != msg.dialog_token) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Ignore Provisioning Discovery Response with " + "P2P: Ignore Provision Discovery Response with " "unexpected Dialog Token %u (expected %u)", msg.dialog_token, dev->dialog_token); p2p_parse_free(&msg); @@ -246,7 +246,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, if (msg.wps_config_methods != dev->req_config_methods) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected " - "our Provisioning Discovery Request"); + "our Provision Discovery Request"); if (p2p->cfg->prov_disc_fail) p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_REJECTED); @@ -267,6 +267,10 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_KEYPAD; } + + /* Store the provisioning info */ + dev->wps_prov_info = msg.wps_config_methods; + p2p_parse_free(&msg); out: @@ -279,25 +283,16 @@ out: int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, - int join) + int join, int force_freq) { struct wpabuf *req; int freq; -#ifdef ANDROID_BRCM_P2P_PATCH - if(dev->go_state == REMOTE_GO) { - wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: GO Sending it to oper_freq %d", dev->oper_freq); - freq= dev->oper_freq; - } - else { - wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: NOT GO oper_freq %d listen_freq %d", dev->oper_freq, dev->listen_freq); - freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; - } -#else - freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; -#endif + if (force_freq > 0) + freq = force_freq; + else + freq = dev->listen_freq > 0 ? dev->listen_freq : + dev->oper_freq; if (freq <= 0) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No Listen/Operating frequency known for the " @@ -345,7 +340,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, - u16 config_methods, int join) + u16 config_methods, int join, int force_freq) { struct p2p_device *dev; @@ -365,6 +360,9 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, if (config_methods == 0) return -1; + /* Reset provisioning info */ + dev->wps_prov_info = 0; + dev->req_config_methods = config_methods; if (join) dev->flags |= P2P_DEV_PD_FOR_JOIN; @@ -391,12 +389,26 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, if (p2p->user_initiated_pd && p2p->state == P2P_IDLE) p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES; - return p2p_send_prov_disc_req(p2p, dev, join); + return p2p_send_prov_disc_req(p2p, dev, join, force_freq); } void p2p_reset_pending_pd(struct p2p_data *p2p) { + struct p2p_device *dev; + + dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { + if (os_memcmp(p2p->pending_pd_devaddr, + dev->info.p2p_device_addr, ETH_ALEN)) + continue; + if (!dev->req_config_methods) + continue; + if (dev->flags & P2P_DEV_PD_FOR_JOIN) + continue; + /* Reset the config methods of the device */ + dev->req_config_methods = 0; + } + p2p->user_initiated_pd = 0; os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN); p2p->pd_retries = 0; diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c index 9e26873..f53d4b5 100644 --- a/src/p2p/p2p_sd.c +++ b/src/p2p/p2p_sd.c @@ -16,6 +16,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" +#include "common/gas.h" #include "p2p_i.h" #include "p2p.h" @@ -26,7 +27,7 @@ struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p, struct p2p_sd_query *q; if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY)) - return 0; /* peer does not support SD */ + return NULL; /* peer does not support SD */ for (q = p2p->sd_queries; q; q = q->next) { if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO)) @@ -90,51 +91,21 @@ static struct wpabuf * p2p_build_sd_query(u16 update_indic, struct wpabuf *tlvs) { struct wpabuf *buf; - u8 *len_pos, *len_pos2; + u8 *len_pos; - buf = wpabuf_alloc(1000 + wpabuf_len(tlvs)); + buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs)); if (buf == NULL) return NULL; - wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); - wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ); - wpabuf_put_u8(buf, 0); /* Dialog Token */ - - /* Advertisement Protocol IE */ - wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); - wpabuf_put_u8(buf, 2); /* Length */ - wpabuf_put_u8(buf, 0); /* QueryRespLenLimit | PAME-BI */ - wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */ - - /* Query Request */ - len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */ - - /* NQP Query Request Frame */ - wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */ - len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */ + /* ANQP Query Request Frame */ + len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, P2P_OUI_TYPE); wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */ wpabuf_put_buf(buf, tlvs); + gas_anqp_set_element_len(buf, len_pos); - WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2); - WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2); - - return buf; -} - - -static struct wpabuf * p2p_build_gas_comeback_req(u8 dialog_token) -{ - struct wpabuf *buf; - - buf = wpabuf_alloc(3); - if (buf == NULL) - return NULL; - - wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); - wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_REQ); - wpabuf_put_u8(buf, dialog_token); + gas_anqp_set_len(buf); return buf; } @@ -145,7 +116,7 @@ static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst, { struct wpabuf *req; - req = p2p_build_gas_comeback_req(dialog_token); + req = gas_build_comeback_req(dialog_token); if (req == NULL) return; @@ -165,42 +136,26 @@ static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code, const struct wpabuf *tlvs) { struct wpabuf *buf; - u8 *len_pos, *len_pos2; + u8 *len_pos; - buf = wpabuf_alloc(1000 + (tlvs ? wpabuf_len(tlvs) : 0)); + buf = gas_anqp_build_initial_resp(dialog_token, status_code, + comeback_delay, + 100 + (tlvs ? wpabuf_len(tlvs) : 0)); if (buf == NULL) return NULL; - wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); - wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP); - wpabuf_put_u8(buf, dialog_token); - wpabuf_put_le16(buf, status_code); - wpabuf_put_le16(buf, comeback_delay); - - /* Advertisement Protocol IE */ - wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); - wpabuf_put_u8(buf, 2); /* Length */ - wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */ - wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */ - - /* Query Response */ - len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */ - if (tlvs) { - /* NQP Query Response Frame */ - wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */ - len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */ + /* ANQP Query Response Frame */ + len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, P2P_OUI_TYPE); /* Service Update Indicator */ wpabuf_put_le16(buf, update_indic); wpabuf_put_buf(buf, tlvs); - - WPA_PUT_LE16(len_pos2, - (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2); + gas_anqp_set_element_len(buf, len_pos); } - WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2); + gas_anqp_set_len(buf); return buf; } @@ -214,31 +169,15 @@ static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token, u16 total_len) { struct wpabuf *buf; - u8 *len_pos; - buf = wpabuf_alloc(1000 + len); + buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id, + more, 0, 100 + len); if (buf == NULL) return NULL; - wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); - wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_RESP); - wpabuf_put_u8(buf, dialog_token); - wpabuf_put_le16(buf, status_code); - wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0)); - wpabuf_put_le16(buf, 0); /* Comeback Delay */ - - /* Advertisement Protocol IE */ - wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); - wpabuf_put_u8(buf, 2); /* Length */ - wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */ - wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */ - - /* Query Response */ - len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */ - if (frag_id == 0) { - /* NQP Query Response Frame */ - wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */ + /* ANQP Query Response Frame */ + wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */ wpabuf_put_le16(buf, 3 + 1 + 2 + total_len); wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, P2P_OUI_TYPE); @@ -247,8 +186,7 @@ static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token, } wpabuf_put_data(buf, data, len); - - WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2); + gas_anqp_set_len(buf); return buf; } @@ -349,7 +287,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa, } pos++; /* skip QueryRespLenLimit and PAME-BI */ - if (*pos != NATIVE_QUERY_PROTOCOL) { + if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported GAS advertisement protocol id %u", *pos); @@ -366,12 +304,12 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa, return; end = pos + slen; - /* NQP Query Request */ + /* ANQP Query Request */ if (pos + 4 > end) return; - if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) { + if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos)); + "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); return; } pos += 2; @@ -380,20 +318,20 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa, pos += 2; if (pos + slen > end || slen < 3 + 1) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Invalid NQP Query Request length"); + "P2P: Invalid ANQP Query Request length"); return; } if (WPA_GET_BE24(pos) != OUI_WFA) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos)); + "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos)); return; } pos += 3; if (*pos != P2P_OUI_TYPE) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Unsupported NQP vendor type %u", *pos); + "P2P: Unsupported ANQP vendor type %u", *pos); return; } pos++; @@ -451,11 +389,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst, p2p->pending_action_state = P2P_NO_PENDING_ACTION; if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, - #ifdef ANDROID_BRCM_P2P_PATCH - p2p->cfg->p2p_dev_addr, - #else p2p->cfg->dev_addr, - #endif wpabuf_head(resp), wpabuf_len(resp), 200) < 0) wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to send Action frame"); @@ -529,7 +463,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, } pos++; /* skip QueryRespLenLimit and PAME-BI */ - if (*pos != NATIVE_QUERY_PROTOCOL) { + if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported GAS advertisement protocol id %u", *pos); @@ -567,12 +501,12 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, return; } - /* NQP Query Response */ + /* ANQP Query Response */ if (pos + 4 > end) return; - if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) { + if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos)); + "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); return; } pos += 2; @@ -581,20 +515,20 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, pos += 2; if (pos + slen > end || slen < 3 + 1) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Invalid NQP Query Response length"); + "P2P: Invalid ANQP Query Response length"); return; } if (WPA_GET_BE24(pos) != OUI_WFA) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos)); + "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos)); return; } pos += 3; if (*pos != P2P_OUI_TYPE) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Unsupported NQP vendor type %u", *pos); + "P2P: Unsupported ANQP vendor type %u", *pos); return; } pos++; @@ -776,7 +710,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, } pos++; /* skip QueryRespLenLimit and PAME-BI */ - if (*pos != NATIVE_QUERY_PROTOCOL) { + if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported GAS advertisement protocol id %u", *pos); @@ -808,29 +742,29 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, if (p2p->sd_rx_resp) { /* - * NQP header is only included in the first fragment; rest of + * ANQP header is only included in the first fragment; rest of * the fragments start with continue TLVs. */ goto skip_nqp_header; } - /* NQP Query Response */ + /* ANQP Query Response */ if (pos + 4 > end) return; - if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) { + if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos)); + "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); return; } pos += 2; slen = WPA_GET_LE16(pos); pos += 2; - wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: NQP Query Response " + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: ANQP Query Response " "length: %u", slen); if (slen < 3 + 1) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Invalid NQP Query Response length"); + "P2P: Invalid ANQP Query Response length"); return; } if (pos + 4 > end) @@ -838,14 +772,14 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, if (WPA_GET_BE24(pos) != OUI_WFA) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos)); + "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos)); return; } pos += 3; if (*pos != P2P_OUI_TYPE) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Unsupported NQP vendor type %u", *pos); + "P2P: Unsupported ANQP vendor type %u", *pos); return; } pos++; diff --git a/src/radius/radius.c b/src/radius/radius.c index 70754ef..3ead847 100644 --- a/src/radius/radius.c +++ b/src/radius/radius.c @@ -218,6 +218,8 @@ static struct radius_attr_type radius_attrs[] = { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP }, { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type", RADIUS_ATTR_HEXDUMP }, + { RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password", + RADIUS_ATTR_UNDIST }, { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT }, { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST }, { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator", @@ -1090,8 +1092,7 @@ radius_msg_add_attr_user_password(struct radius_msg *msg, const u8 *secret, size_t secret_len) { u8 buf[128]; - int padlen, i; - size_t buf_len, pos; + size_t padlen, i, buf_len, pos; const u8 *addr[2]; size_t len[2]; u8 hash[16]; @@ -1103,7 +1104,7 @@ radius_msg_add_attr_user_password(struct radius_msg *msg, buf_len = data_len; padlen = data_len % 16; - if (padlen) { + if (padlen && data_len < sizeof(buf)) { padlen = 16 - padlen; os_memset(buf + data_len, 0, padlen); buf_len += padlen; @@ -1276,6 +1277,120 @@ int radius_msg_get_vlanid(struct radius_msg *msg) } +/** + * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password + * @msg: Received RADIUS message + * @keylen: Length of returned password + * @secret: RADIUS shared secret + * @secret_len: Length of secret + * @sent_msg: Sent RADIUS message + * Returns: pointer to password (free with os_free) or %NULL + */ +char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen, + const u8 *secret, size_t secret_len, + struct radius_msg *sent_msg) +{ + u8 *buf = NULL; + size_t buflen; + const u8 *salt; + u8 *str; + const u8 *addr[3]; + size_t len[3]; + u8 hash[16]; + u8 *pos; + size_t i; + struct radius_attr_hdr *attr; + const u8 *data; + size_t dlen; + const u8 *fdata = NULL; /* points to found item */ + size_t fdlen = -1; + char *ret = NULL; + + /* find attribute with lowest tag and check it */ + for (i = 0; i < msg->attr_used; i++) { + attr = radius_get_attr_hdr(msg, i); + if (attr == NULL || + attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) { + continue; + } + if (attr->length <= 5) + continue; + data = (const u8 *) (attr + 1); + dlen = attr->length - sizeof(*attr); + if (dlen <= 3 || dlen % 16 != 3) + continue; + if (fdata != NULL && fdata[0] <= data[0]) + continue; + + fdata = data; + fdlen = dlen; + } + if (fdata == NULL) + goto out; + + /* alloc writable memory for decryption */ + buf = os_malloc(fdlen); + if (buf == NULL) + goto out; + os_memcpy(buf, fdata, fdlen); + buflen = fdlen; + + /* init pointers */ + salt = buf + 1; + str = buf + 3; + + /* decrypt blocks */ + pos = buf + buflen - 16; /* last block */ + while (pos >= str + 16) { /* all but the first block */ + addr[0] = secret; + len[0] = secret_len; + addr[1] = pos - 16; + len[1] = 16; + md5_vector(2, addr, len, hash); + + for (i = 0; i < 16; i++) + pos[i] ^= hash[i]; + + pos -= 16; + } + + /* decrypt first block */ + if (str != pos) + goto out; + addr[0] = secret; + len[0] = secret_len; + addr[1] = sent_msg->hdr->authenticator; + len[1] = 16; + addr[2] = salt; + len[2] = 2; + md5_vector(3, addr, len, hash); + + for (i = 0; i < 16; i++) + pos[i] ^= hash[i]; + + /* derive plaintext length from first subfield */ + *keylen = (unsigned char) str[0]; + if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) { + /* decryption error - invalid key length */ + goto out; + } + if (*keylen == 0) { + /* empty password */ + goto out; + } + + /* copy passphrase into new buffer */ + ret = os_malloc(*keylen); + if (ret) + os_memcpy(ret, str + 1, *keylen); + +out: + /* return new buffer */ + os_free(buf); + return ret; +} + + void radius_free_class(struct radius_class_data *c) { size_t i; diff --git a/src/radius/radius.h b/src/radius/radius.h index a3cdac0..e69a047 100644 --- a/src/radius/radius.h +++ b/src/radius/radius.h @@ -82,6 +82,7 @@ enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_NAS_PORT_TYPE = 61, RADIUS_ATTR_TUNNEL_TYPE = 64, RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65, + RADIUS_ATTR_TUNNEL_PASSWORD = 69, RADIUS_ATTR_CONNECT_INFO = 77, RADIUS_ATTR_EAP_MESSAGE = 79, RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80, @@ -231,6 +232,9 @@ radius_msg_add_attr_user_password(struct radius_msg *msg, 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); +char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen, + const u8 *secret, size_t secret_len, + struct radius_msg *sent_msg); static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type, u32 value) diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index 6f1c3a5..47948bc 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -1,6 +1,6 @@ /* * RADIUS authentication server - * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -292,6 +292,10 @@ struct radius_server_data { * msg_ctx - Context data for wpa_msg() calls */ void *msg_ctx; + +#ifdef CONFIG_RADIUS_TEST + char *dump_msk_file; +#endif /* CONFIG_RADIUS_TEST */ }; @@ -574,6 +578,24 @@ radius_server_encapsulate_eap(struct radius_server_data *data, if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) { int len; +#ifdef CONFIG_RADIUS_TEST + if (data->dump_msk_file) { + FILE *f; + char buf[2 * 64 + 1]; + f = fopen(data->dump_msk_file, "a"); + if (f) { + len = sess->eap_if->eapKeyDataLen; + if (len > 64) + len = 64; + len = wpa_snprintf_hex( + buf, sizeof(buf), + sess->eap_if->eapKeyData, len); + buf[len] = '\0'; + fprintf(f, "%s\n", buf); + fclose(f); + } + } +#endif /* CONFIG_RADIUS_TEST */ if (sess->eap_if->eapKeyDataLen > 64) { len = 32; } else { @@ -1277,6 +1299,11 @@ radius_server_init(struct radius_server_conf *conf) } } +#ifdef CONFIG_RADIUS_TEST + if (conf->dump_msk_file) + data->dump_msk_file = os_strdup(conf->dump_msk_file); +#endif /* CONFIG_RADIUS_TEST */ + data->clients = radius_server_read_clients(conf->client_file, conf->ipv6); if (data->clients == NULL) { @@ -1328,6 +1355,9 @@ void radius_server_deinit(struct radius_server_data *data) os_free(data->eap_fast_a_id); os_free(data->eap_fast_a_id_info); os_free(data->eap_req_id_text); +#ifdef CONFIG_RADIUS_TEST + os_free(data->dump_msk_file); +#endif /* CONFIG_RADIUS_TEST */ os_free(data); } diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h index 126e314..8d6e2ab 100644 --- a/src/radius/radius_server.h +++ b/src/radius/radius_server.h @@ -1,6 +1,6 @@ /* * RADIUS authentication server - * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -201,6 +201,10 @@ struct radius_server_conf { * msg_ctx - Context data for wpa_msg() calls */ void *msg_ctx; + +#ifdef CONFIG_RADIUS_TEST + const char *dump_msk_file; +#endif /* CONFIG_RADIUS_TEST */ }; diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index cac8c83..3877efb 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -49,6 +49,7 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, struct rsn_pmksa_cache_entry *entry, int replace) { + wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid); pmksa->pmksa_count--; pmksa->free_cb(entry, pmksa->ctx, replace); _pmksa_cache_free_entry(entry); @@ -185,6 +186,14 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " "the current AP"); pmksa_cache_free_entry(pmksa, pos, 1); + + /* + * If OKC is used, there may be other PMKSA cache + * entries based on the same PMK. These needs to be + * flushed so that a new entry can be created based on + * the new PMK. + */ + pmksa_cache_flush(pmksa, network_ctx); break; } prev = pos; @@ -198,7 +207,6 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache " "entry (for " MACSTR ") to make room for new one", MAC2STR(pos->aa)); - wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid); pmksa_cache_free_entry(pmksa, pos, 0); } @@ -229,6 +237,39 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, /** + * pmksa_cache_flush - Flush PMKSA cache entries for a specific network + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * @network_ctx: Network configuration context or %NULL to flush all entries + */ +void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx) +{ + struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp; + int removed = 0; + + entry = pmksa->pmksa; + while (entry) { + if (entry->network_ctx == network_ctx || network_ctx == NULL) { + wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry " + "for " MACSTR, MAC2STR(entry->aa)); + if (prev) + prev->next = entry->next; + else + pmksa->pmksa = entry->next; + tmp = entry; + entry = entry->next; + pmksa_cache_free_entry(pmksa, tmp, 0); + removed++; + } else { + prev = entry; + entry = entry->next; + } + } + if (removed) + pmksa_cache_set_expiration(pmksa); +} + + +/** * pmksa_cache_deinit - Free all entries in PMKSA cache * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() */ @@ -273,22 +314,6 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, } -/** - * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() - * - * Clear references to old data structures when wpa_supplicant is reconfigured. - */ -void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa) -{ - struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; - while (entry) { - entry->network_ctx = NULL; - entry = entry->next; - } -} - - static struct rsn_pmksa_cache_entry * pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, const struct rsn_pmksa_cache_entry *old_entry, @@ -327,6 +352,7 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, { struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; + wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa)); if (network_ctx == NULL) return NULL; while (entry) { diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h index a1447e5..840827d 100644 --- a/src/rsn_supp/pmksa_cache.h +++ b/src/rsn_supp/pmksa_cache.h @@ -57,7 +57,6 @@ 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 *aa, const u8 *spa, void *network_ctx, int akmp); -void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa); struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm); void pmksa_cache_clear_current(struct wpa_sm *sm); int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, @@ -66,6 +65,7 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, const u8 *aa); +void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx); #else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ @@ -106,10 +106,6 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, return NULL; } -static inline void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa) -{ -} - static inline void pmksa_cache_clear_current(struct wpa_sm *sm) { } @@ -122,6 +118,11 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, return -1; } +static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, + void *network_ctx) +{ +} + #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ #endif /* PMKSA_CACHE_H */ diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c index 6109f5e..fefca83 100644 --- a/src/rsn_supp/preauth.c +++ b/src/rsn_supp/preauth.c @@ -22,7 +22,6 @@ #include "preauth.h" #include "pmksa_cache.h" #include "wpa_i.h" -#include "common/ieee802_11_defs.h" #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index e751867..27090e3 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -88,6 +88,8 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer); #define TDLS_MAX_IE_LEN 80 +#define IEEE80211_MAX_SUPP_RATES 32 + struct wpa_tdls_peer { struct wpa_tdls_peer *next; int initiator; /* whether this end was initiator for TDLS setup */ @@ -119,6 +121,11 @@ struct wpa_tdls_peer { int buf_len; /* length of TPK message for retransmission */ u8 *buf; /* buffer for TPK message */ } sm_tmr; + + u16 capability; + + u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; + size_t supp_rates_len; }; @@ -214,7 +221,9 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, } if (action_code == WLAN_TDLS_SETUP_CONFIRM || - action_code == WLAN_TDLS_TEARDOWN) + action_code == WLAN_TDLS_TEARDOWN || + action_code == WLAN_TDLS_DISCOVERY_REQUEST || + action_code == WLAN_TDLS_DISCOVERY_RESPONSE) return 0; /* No retries */ for (peer = sm->tdls; peer; peer = peer->next) { @@ -253,6 +262,27 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, } +static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer, + u16 reason_code, int free_peer) +{ + int ret; + + if (sm->tdls_external_setup) { + ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code); + + /* disable the link after teardown was sent */ + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); + } else { + ret = wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); + } + + if (sm->tdls_external_setup || free_peer) + wpa_tdls_peer_free(sm, peer); + + return ret; +} + + static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) { @@ -291,15 +321,11 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) eloop_register_timeout(peer->sm_tmr.timer / 1000, 0, wpa_tdls_tpk_retry_timeout, sm, peer); } else { - wpa_printf(MSG_INFO, "Sending Tear_Down Request"); - wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); - - wpa_printf(MSG_INFO, "Clearing SM: Peerkey(" MACSTR ")", - MAC2STR(peer->addr)); eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - /* clear the Peerkey statemachine */ - wpa_tdls_peer_free(sm, peer); + wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request"); + wpa_tdls_do_teardown(sm, peer, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1); } } @@ -576,7 +602,8 @@ static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx) } else { wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR " - tear down", MAC2STR(peer->addr)); - wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); + wpa_tdls_do_teardown(sm, peer, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1); } } @@ -615,8 +642,7 @@ static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer, } -int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr, - u16 reason_code) +int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code) { struct wpa_tdls_peer *peer; struct wpa_tdls_ftie *ftie; @@ -625,7 +651,7 @@ int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr, u8 *rbuf, *pos; int ielen; - if (sm->tdls_disabled) + if (sm->tdls_disabled || !sm->tdls_supported) return -1; /* Find the node and free from the list */ @@ -677,10 +703,11 @@ int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr, ftie->ie_len += 170; *pos++ = 255; /* FTIE subelem */ *pos++ = 168; /* FTIE subelem length */ + pos += 168; } #endif /* CONFIG_TDLS_TESTING */ wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake", - (u8 *) ftie, sizeof(*ftie)); + (u8 *) ftie, pos - (u8 *) ftie); /* compute MIC before sending */ wpa_tdls_linkid(sm, peer, &lnkid); @@ -705,6 +732,50 @@ skip_ies: } +int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code) +{ + struct wpa_tdls_peer *peer; + + if (sm->tdls_disabled || !sm->tdls_supported) + return -1; + + for (peer = sm->tdls; peer; peer = peer->next) { + if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) + break; + } + + if (peer == NULL) { + wpa_printf(MSG_DEBUG, "TDLS: Could not find peer " MACSTR + " for link Teardown", MAC2STR(addr)); + return -1; + } + + if (!peer->tpk_success) { + wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR + " not connected - cannot Teardown link", MAC2STR(addr)); + return -1; + } + + return wpa_tdls_do_teardown(sm, peer, reason_code, 0); +} + + +void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr) +{ + struct wpa_tdls_peer *peer; + + for (peer = sm->tdls; peer; peer = peer->next) { + if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) + break; + } + + if (peer) { + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr); + wpa_tdls_peer_free(sm, peer); + } +} + + static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len) { @@ -802,6 +873,26 @@ static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst, } +static struct wpa_tdls_peer * +wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr) +{ + struct wpa_tdls_peer *peer; + + wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR, + MAC2STR(addr)); + + peer = os_zalloc(sizeof(*peer)); + if (peer == NULL) + return NULL; + + os_memcpy(peer->addr, addr, ETH_ALEN); + peer->next = sm->tdls; + sm->tdls = peer; + + return peer; +} + + static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm, struct wpa_tdls_peer *peer) { @@ -972,7 +1063,7 @@ skip_ies: "Handshake Message 1 (peer " MACSTR ")", MAC2STR(peer->addr)); - wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 0, 0, + wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1, 0, rbuf, pos - rbuf); os_free(rbuf); @@ -1144,6 +1235,105 @@ skip_ies: } +static int wpa_tdls_send_discovery_response(struct wpa_sm *sm, + struct wpa_tdls_peer *peer, + u8 dialog_token) +{ + wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response " + "(peer " MACSTR ")", MAC2STR(peer->addr)); + + return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE, + dialog_token, 0, NULL, 0); +} + + +static int +wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr, + const u8 *buf, size_t len) +{ + struct wpa_eapol_ie_parse kde; + const struct wpa_tdls_lnkid *lnkid; + struct wpa_tdls_peer *peer; + size_t min_req_len = sizeof(struct wpa_tdls_frame) + + 1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid); + u8 dialog_token; + + wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR, + MAC2STR(addr)); + + if (len < min_req_len) { + wpa_printf(MSG_DEBUG, "TDLS Discovery Request is too short: " + "%d", (int) len); + return -1; + } + + dialog_token = buf[sizeof(struct wpa_tdls_frame)]; + + if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1, + len - (sizeof(struct wpa_tdls_frame) + 1), + &kde) < 0) + return -1; + + if (!kde.lnkid) { + wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery " + "Request"); + return -1; + } + + lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid; + + if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different " + " BSS " MACSTR, MAC2STR(lnkid->bssid)); + return -1; + } + + peer = wpa_tdls_add_peer(sm, addr); + if (peer == NULL) + return -1; + + return wpa_tdls_send_discovery_response(sm, peer, dialog_token); +} + + +int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr) +{ + if (sm->tdls_disabled || !sm->tdls_supported) + return -1; + + wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer " + MACSTR, MAC2STR(addr)); + return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST, + 1, 0, NULL, 0); +} + + +static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde, + struct wpa_tdls_peer *peer) +{ + if (!kde->supp_rates) { + wpa_printf(MSG_DEBUG, "TDLS: No supported rates received"); + return -1; + } + + peer->supp_rates_len = kde->supp_rates_len - 2; + if (peer->supp_rates_len > IEEE80211_MAX_SUPP_RATES) + peer->supp_rates_len = IEEE80211_MAX_SUPP_RATES; + os_memcpy(peer->supp_rates, kde->supp_rates + 2, peer->supp_rates_len); + + if (kde->ext_supp_rates) { + int clen = kde->ext_supp_rates_len - 2; + if (peer->supp_rates_len + clen > IEEE80211_MAX_SUPP_RATES) + clen = IEEE80211_MAX_SUPP_RATES - peer->supp_rates_len; + os_memcpy(peer->supp_rates + peer->supp_rates_len, + kde->ext_supp_rates + 2, clen); + peer->supp_rates_len += clen; + } + + return 0; +} + + static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len) { @@ -1166,6 +1356,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, u16 ielen; u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE; int tdls_prohibited = sm->tdls_prohibited; + int existing_peer = 0; if (len < 3 + 3) return -1; @@ -1178,7 +1369,22 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken); - cpos += 2; /* capability information */ + for (peer = sm->tdls; peer; peer = peer->next) { + if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) { + existing_peer = 1; + break; + } + } + + if (peer == NULL) { + peer = wpa_tdls_add_peer(sm, src_addr); + if (peer == NULL) + goto error; + } + + /* capability information */ + peer->capability = WPA_GET_LE16(cpos); + cpos += 2; ielen = len - (cpos - buf); /* start of IE in buf */ if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) { @@ -1203,6 +1409,9 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR, MAC2STR(src_addr)); + if (copy_supp_rates(&kde, peer) < 0) + goto error; + #ifdef CONFIG_TDLS_TESTING if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { for (peer = sm->tdls; peer; peer = peer->next) { @@ -1210,12 +1419,9 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, break; } if (peer == NULL) { - peer = os_zalloc(sizeof(*peer)); + peer = wpa_tdls_add_peer(sm, src_addr); if (peer == NULL) goto error; - os_memcpy(peer->addr, src_addr, ETH_ALEN); - peer->next = sm->tdls; - sm->tdls = peer; } wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of " "TDLS setup - send own request"); @@ -1302,26 +1508,10 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, } skip_rsn: - /* Find existing entry and if found, use that instead of adding - * a new one; how to handle the case where both ends initiate at the + /* If found, use existing entry instead of adding a new one; + * how to handle the case where both ends initiate at the * same time? */ - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) - break; - } - - if (peer == NULL) { - wpa_printf(MSG_INFO, "TDLS: No matching entry found for " - "peer, creating one for " MACSTR, - MAC2STR(src_addr)); - peer = os_malloc(sizeof(*peer)); - if (peer == NULL) - goto error; - os_memset(peer, 0, sizeof(*peer)); - os_memcpy(peer->addr, src_addr, ETH_ALEN); - peer->next = sm->tdls; - sm->tdls = peer; - } else { + if (existing_peer) { if (peer->tpk_success) { wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while " "direct link is enabled - tear down the " @@ -1332,7 +1522,11 @@ skip_rsn: * some drivers handling the new request frame. */ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); #else - wpa_tdls_del_key(sm, peer); + if (sm->tdls_external_setup) + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, + src_addr); + else + wpa_tdls_del_key(sm, peer); #endif wpa_tdls_peer_free(sm, peer); } @@ -1360,6 +1554,19 @@ skip_rsn: } } +#ifdef CONFIG_TDLS_TESTING + if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { + if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) { + /* + * The request frame from us is going to win, so do not + * replace information based on this request frame from + * the peer. + */ + goto skip_rsn_check; + } + } +#endif /* CONFIG_TDLS_TESTING */ + peer->initiator = 0; /* Need to check */ peer->dtoken = dtoken; @@ -1433,8 +1640,14 @@ skip_rsn: wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); skip_rsn_check: + /* add the peer to the driver as a "setup in progress" peer */ + wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0); + wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2"); - wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer); + if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) { + wpa_tdls_disable_link(sm, peer->addr); + goto error; + } return 0; @@ -1467,6 +1680,11 @@ static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) } #endif /* CONFIG_TDLS_TESTING */ } + + /* add supported rates and capabilities to the TDLS peer */ + wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability, + peer->supp_rates, peer->supp_rates_len); + wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr); } @@ -1510,6 +1728,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, if (status != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u", status); + if (sm->tdls_external_setup) + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); return -1; } @@ -1522,7 +1742,10 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, if (len < 3 + 2 + 1 + 2) return -1; - pos += 2; /* capability information */ + + /* capability information */ + peer->capability = WPA_GET_LE16(pos); + pos += 2; ielen = len - (pos - buf); /* start of IE in buf */ if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) { @@ -1553,6 +1776,9 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, goto error; } + if (copy_supp_rates(&kde, peer) < 0) + goto error; + if (!wpa_tdls_get_privacy(sm)) { peer->rsnie_p_len = 0; peer->cipher = WPA_CIPHER_NONE; @@ -1644,6 +1870,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, /* Discard the frame */ wpa_tdls_del_key(sm, peer); wpa_tdls_peer_free(sm, peer); + if (sm->tdls_external_setup) + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); return -1; } @@ -1663,6 +1891,8 @@ skip_rsn: error: wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, status); + if (sm->tdls_external_setup) + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); return -1; } @@ -1703,6 +1933,8 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, if (status != 0) { wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u", status); + if (sm->tdls_external_setup) + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); return -1; } pos += 2 /* status code */ + 1 /* dialog token */; @@ -1775,6 +2007,8 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, if (lifetime != peer->lifetime) { wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " "TPK M3 (expected %u)", lifetime, peer->lifetime); + if (sm->tdls_external_setup) + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); return -1; } @@ -1823,7 +2057,7 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) struct wpa_tdls_peer *peer; int tdls_prohibited = sm->tdls_prohibited; - if (sm->tdls_disabled) + if (sm->tdls_disabled || !sm->tdls_supported) return -1; #ifdef CONFIG_TDLS_TESTING @@ -1849,20 +2083,22 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) } if (peer == NULL) { - wpa_printf(MSG_INFO, "TDLS: No matching entry found for " - "peer, creating one for " MACSTR, MAC2STR(addr)); - peer = os_malloc(sizeof(*peer)); + peer = wpa_tdls_add_peer(sm, addr); if (peer == NULL) return -1; - os_memset(peer, 0, sizeof(*peer)); - os_memcpy(peer->addr, addr, ETH_ALEN); - peer->next = sm->tdls; - sm->tdls = peer; } peer->initiator = 1; - return wpa_tdls_send_tpk_m1(sm, peer); + /* add the peer to the driver as a "setup in progress" peer */ + wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0); + + if (wpa_tdls_send_tpk_m1(sm, peer) < 0) { + wpa_tdls_disable_link(sm, peer->addr); + return -1; + } + + return 0; } @@ -1870,7 +2106,7 @@ int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr) { struct wpa_tdls_peer *peer; - if (sm->tdls_disabled) + if (sm->tdls_disabled || !sm->tdls_supported) return -1; for (peer = sm->tdls; peer; peer = peer->next) { @@ -1881,6 +2117,14 @@ int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr) if (peer == NULL || !peer->tpk_success) return -1; + if (sm->tdls_external_setup) { + /* + * Disable previous link to allow renegotiation to be completed + * on AP path. + */ + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); + } + return wpa_tdls_start(sm, addr); } @@ -1899,8 +2143,9 @@ static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr, wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation", buf, len); - if (sm->tdls_disabled) { - wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled"); + if (sm->tdls_disabled || !sm->tdls_supported) { + wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled " + "or unsupported by driver"); return; } @@ -1937,6 +2182,9 @@ static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr, case WLAN_TDLS_TEARDOWN: wpa_tdls_recv_teardown(sm, src_addr, buf, len); break; + case WLAN_TDLS_DISCOVERY_REQUEST: + wpa_tdls_process_discovery_request(sm, src_addr, buf, len); + break; default: /* Kernel code will process remaining frames */ wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u", @@ -1969,6 +2217,21 @@ int wpa_tdls_init(struct wpa_sm *sm) return -1; } + /* + * Drivers that support TDLS but don't implement the get_capa callback + * are assumed to perform everything internally + */ + if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported, + &sm->tdls_external_setup) < 0) { + sm->tdls_supported = 1; + sm->tdls_external_setup = 0; + } + + wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by " + "driver", sm->tdls_supported ? "" : " not"); + wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup", + sm->tdls_external_setup ? "external" : "internal"); + return 0; } @@ -2067,3 +2330,9 @@ void wpa_tdls_enable(struct wpa_sm *sm, int enabled) wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled"); sm->tdls_disabled = !enabled; } + + +int wpa_tdls_is_external_setup(struct wpa_sm *sm) +{ + return sm->tdls_external_setup; +} diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 7c0ac87..f35f9ee 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -396,7 +396,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, const u8 *_buf = (const u8 *) (key + 1); size_t len = WPA_GET_BE16(key->key_data_length); wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len); - wpa_supplicant_parse_ies(_buf, len, &ie); + if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0) + goto failed; if (ie.pmkid) { wpa_hexdump(MSG_DEBUG, "RSN: PMKID from " "Authenticator", ie.pmkid, PMKID_LEN); @@ -476,7 +477,7 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, * Start preauthentication after a short wait to avoid a * possible race condition between the data receive and key * configuration after the 4-Way Handshake. This increases the - * likelyhood of the first preauth EAPOL-Start frame getting to + * likelihood of the first preauth EAPOL-Start frame getting to * the target AP. */ eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL); @@ -1085,7 +1086,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, pos = (const u8 *) (key + 1); len = WPA_GET_BE16(key->key_data_length); wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len); - wpa_supplicant_parse_ies(pos, len, &ie); + if (wpa_supplicant_parse_ies(pos, len, &ie) < 0) + goto failed; if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: GTK IE in unencrypted key data"); @@ -1174,6 +1176,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, goto failed; } + wpa_sm_set_rekey_offload(sm); + return; failed: @@ -1191,7 +1195,8 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm, struct wpa_eapol_ie_parse ie; wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen); - wpa_supplicant_parse_ies(keydata, keydatalen, &ie); + if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0) + return -1; if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: GTK IE in unencrypted key data"); @@ -1392,6 +1397,8 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher)); wpa_sm_cancel_auth_timeout(sm); wpa_sm_set_state(sm, WPA_COMPLETED); + + wpa_sm_set_rekey_offload(sm); } else { wpa_supplicant_key_neg_complete(sm, sm->bssid, key_info & @@ -2265,8 +2272,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->ssid_len = 0; sm->wpa_ptk_rekey = 0; } - if (config == NULL || config->network_ctx != sm->network_ctx) - pmksa_cache_notify_reconfig(sm->pmksa); } @@ -2644,3 +2649,17 @@ int wpa_sm_has_ptk(struct wpa_sm *sm) return 0; return sm->ptk_set; } + + +void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr) +{ + os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN); +} + + +void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx) +{ +#ifndef CONFIG_NO_WPA2 + pmksa_cache_flush(sm->pmksa, network_ctx); +#endif /* CONFIG_NO_WPA2 */ +} diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 111597c..4c1750f 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -56,11 +56,18 @@ struct wpa_sm_ctx { const u8 *ies, size_t ies_len); int (*mark_authenticated)(void *ctx, const u8 *target_ap); #ifdef CONFIG_TDLS + int (*tdls_get_capa)(void *ctx, int *tdls_supported, + int *tdls_ext_setup); int (*send_tdls_mgmt)(void *ctx, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, const u8 *buf, size_t len); int (*tdls_oper)(void *ctx, int oper, const u8 *peer); + int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, + u16 capability, const u8 *supp_rates, + size_t supp_rates_len); #endif /* CONFIG_TDLS */ + void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck, + const u8 *replay_ctr); }; @@ -132,6 +139,10 @@ int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len); void wpa_sm_drop_sa(struct wpa_sm *sm); int wpa_sm_has_ptk(struct wpa_sm *sm); +void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr); + +void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx); + #else /* CONFIG_NO_WPA */ static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) @@ -277,6 +288,16 @@ static inline int wpa_sm_has_ptk(struct wpa_sm *sm) return 0; } +static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm, + const u8 *replay_ctr) +{ +} + +static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, + void *network_ctx) +{ +} + #endif /* CONFIG_NO_WPA */ #ifdef CONFIG_PEERKEY @@ -342,10 +363,13 @@ void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len); void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len); int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr); int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr); -int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr, - u16 reason_code); +int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code); +int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code); +int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr); int wpa_tdls_init(struct wpa_sm *sm); void wpa_tdls_deinit(struct wpa_sm *sm); void wpa_tdls_enable(struct wpa_sm *sm, int enabled); +void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr); +int wpa_tdls_is_external_setup(struct wpa_sm *sm); #endif /* WPA_H */ diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index da6e966..dbf5996 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -21,35 +21,9 @@ #include "common/ieee802_11_common.h" #include "wpa.h" #include "wpa_i.h" -#include "wpa_ie.h" #ifdef CONFIG_IEEE80211R -struct wpa_ft_ies { - const u8 *mdie; - size_t mdie_len; - const u8 *ftie; - size_t ftie_len; - const u8 *r1kh_id; - const u8 *gtk; - size_t gtk_len; - const u8 *r0kh_id; - size_t r0kh_id_len; - const u8 *rsn; - size_t rsn_len; - const u8 *rsn_pmkid; - const u8 *tie; - size_t tie_len; - const u8 *igtk; - size_t igtk_len; - const u8 *ric; - size_t ric_len; -}; - -static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, - struct wpa_ft_ies *parse); - - int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, struct wpa_ptk *ptk, size_t ptk_len) @@ -347,155 +321,6 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, } -static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, - struct wpa_ft_ies *parse) -{ - const u8 *end, *pos; - - parse->ftie = ie; - parse->ftie_len = ie_len; - - pos = ie + sizeof(struct rsn_ftie); - end = ie + ie_len; - - while (pos + 2 <= end && pos + 2 + pos[1] <= end) { - switch (pos[0]) { - 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]); - return -1; - } - parse->r1kh_id = pos + 2; - break; - case FTIE_SUBELEM_GTK: - parse->gtk = pos + 2; - parse->gtk_len = pos[1]; - 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]); - return -1; - } - parse->r0kh_id = pos + 2; - parse->r0kh_id_len = pos[1]; - break; -#ifdef CONFIG_IEEE80211W - case FTIE_SUBELEM_IGTK: - parse->igtk = pos + 2; - parse->igtk_len = pos[1]; - break; -#endif /* CONFIG_IEEE80211W */ - } - - pos += 2 + pos[1]; - } - - return 0; -} - - -static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, - struct wpa_ft_ies *parse) -{ - const u8 *end, *pos; - struct wpa_ie_data data; - int ret; - const struct rsn_ftie *ftie; - int prot_ie_count = 0; - - os_memset(parse, 0, sizeof(*parse)); - if (ies == NULL) - return 0; - - pos = ies; - end = ies + ies_len; - while (pos + 2 <= end && pos + 2 + pos[1] <= end) { - switch (pos[0]) { - case WLAN_EID_RSN: - parse->rsn = pos + 2; - parse->rsn_len = pos[1]; - ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, - parse->rsn_len + 2, - &data); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to parse " - "RSN IE: %d", ret); - return -1; - } - if (data.num_pmkid == 1 && data.pmkid) - parse->rsn_pmkid = data.pmkid; - break; - case WLAN_EID_MOBILITY_DOMAIN: - parse->mdie = pos + 2; - parse->mdie_len = pos[1]; - break; - case WLAN_EID_FAST_BSS_TRANSITION: - if (pos[1] < sizeof(*ftie)) - return -1; - ftie = (const struct rsn_ftie *) (pos + 2); - prot_ie_count = ftie->mic_control[1]; - if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) - return -1; - break; - case WLAN_EID_TIMEOUT_INTERVAL: - parse->tie = pos + 2; - parse->tie_len = pos[1]; - break; - case WLAN_EID_RIC_DATA: - if (parse->ric == NULL) - parse->ric = pos; - } - - pos += 2 + pos[1]; - } - - if (prot_ie_count == 0) - return 0; /* no MIC */ - - /* - * Check that the protected IE count matches with IEs included in the - * frame. - */ - if (parse->rsn) - prot_ie_count--; - if (parse->mdie) - prot_ie_count--; - if (parse->ftie) - prot_ie_count--; - if (parse->tie) - prot_ie_count--; - if (prot_ie_count < 0) { - wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " - "the protected IE count"); - return -1; - } - - if (prot_ie_count == 0 && parse->ric) { - wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " - "included in protected IE count"); - return -1; - } - - /* 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]; - } - 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); - return -1; - } - - return 0; -} - - static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) { int keylen; @@ -950,8 +775,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, } count = 3; - if (parse.tie) - count++; + if (parse.ric) + count += ieee802_11_ie_count(parse.ric, parse.ric_len); if (ftie->mic_control[1] != count) { wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " "Control: received %u expected %u", diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 09a2e4f..39124c4 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -98,6 +98,15 @@ struct wpa_sm { struct wpa_tdls_peer *tdls; int tdls_prohibited; int tdls_disabled; + + /* The driver supports TDLS */ + int tdls_supported; + + /* + * The driver requires explicit discovery/setup/teardown frames sent + * to it via tdls_mgmt. + */ + int tdls_external_setup; #endif /* CONFIG_TDLS */ #ifdef CONFIG_IEEE80211R @@ -244,7 +253,25 @@ static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm, return -1; } +static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm) +{ + if (!sm->ctx->set_rekey_offload) + return; + sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek, + sm->ptk.kck, sm->rx_replay_counter); +} + #ifdef CONFIG_TDLS +static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm, + int *tdls_supported, + int *tdls_ext_setup) +{ + if (sm->ctx->tdls_get_capa) + return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported, + tdls_ext_setup); + return -1; +} + static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, const u8 *buf, @@ -264,6 +291,18 @@ static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper, return sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer); return -1; } + +static inline int +wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add, + u16 capability, const u8 *supp_rates, + size_t supp_rates_len) +{ + if (sm->ctx->tdls_peer_addset) + return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add, + capability, supp_rates, + supp_rates_len); + return -1; +} #endif /* CONFIG_TDLS */ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 654cc1f..cbbc54f 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -424,11 +424,19 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, pos, 2 + pos[1]); } } else if (*pos == WLAN_EID_LINK_ID) { - ie->lnkid = pos; - ie->lnkid_len = pos[1] + 2; + if (pos[1] >= 18) { + ie->lnkid = pos; + ie->lnkid_len = pos[1] + 2; + } } else if (*pos == WLAN_EID_EXT_CAPAB) { ie->ext_capab = pos; ie->ext_capab_len = pos[1] + 2; + } else if (*pos == WLAN_EID_SUPP_RATES) { + ie->supp_rates = pos; + ie->supp_rates_len = pos[1] + 2; + } else if (*pos == WLAN_EID_EXT_SUPP_RATES) { + ie->ext_supp_rates = pos; + ie->ext_supp_rates_len = pos[1] + 2; } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { ret = wpa_parse_generic(pos, end, ie); if (ret < 0) diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h index f939b13..c13d94c 100644 --- a/src/rsn_supp/wpa_ie.h +++ b/src/rsn_supp/wpa_ie.h @@ -51,6 +51,10 @@ struct wpa_eapol_ie_parse { size_t lnkid_len; const u8 *ext_capab; size_t ext_capab_len; + const u8 *supp_rates; + size_t supp_rates_len; + const u8 *ext_supp_rates; + size_t ext_supp_rates_len; }; int wpa_supplicant_parse_ies(const u8 *buf, size_t len, diff --git a/src/tls/Makefile b/src/tls/Makefile index a2da096..27cdfca 100644 --- a/src/tls/Makefile +++ b/src/tls/Makefile @@ -11,6 +11,8 @@ include ../lib.rules CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH CFLAGS += -DCONFIG_CRYPTO_INTERNAL +CFLAGS += -DCONFIG_TLSV11 +CFLAGS += -DCONFIG_TLSV12 LIB_OBJS= \ asn1.o \ diff --git a/src/tls/libtommath.c b/src/tls/libtommath.c index 1374264..7c9857f 100644 --- a/src/tls/libtommath.c +++ b/src/tls/libtommath.c @@ -572,7 +572,7 @@ static int mp_mod (mp_int * a, mp_int * b, mp_int * c) /* this is a shell function that calls either the normal or Montgomery * exptmod functions. Originally the call to the montgomery code was - * embedded in the normal function but that wasted alot of stack space + * embedded in the normal function but that wasted a lot of stack space * for nothing (since 99% of the time the Montgomery code would be called) */ static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) @@ -2207,7 +2207,7 @@ static int mp_2expt (mp_int * a, int b) /* zero a as per default */ mp_zero (a); - /* grow a to accomodate the single bit */ + /* grow a to accommodate the single bit */ if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { return res; } @@ -2319,7 +2319,7 @@ CLEANUP: } -/* multiplies |a| * |b| and only computes upto digs digits of result +/* multiplies |a| * |b| and only computes up to digs digits of result * HAC pp. 595, Algorithm 14.12 Modified so you can control how * many digits of output are created. */ @@ -2678,7 +2678,7 @@ mp_montgomery_setup (mp_int * n, mp_digit * rho) * * Based on Algorithm 14.32 on pp.601 of HAC. */ -int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +static int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) { int ix, res, olduse; mp_word W[MP_WARRAY]; @@ -2829,7 +2829,7 @@ static int mp_mul_2(mp_int * a, mp_int * b) { int x, res, oldused; - /* grow to accomodate result */ + /* grow to accommodate result */ if (b->alloc < a->used + 1) { if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { return res; @@ -2891,8 +2891,8 @@ static int mp_mul_2(mp_int * a, mp_int * b) /* * shifts with subtractions when the result is greater than b. * - * The method is slightly modified to shift B unconditionally upto just under - * the leading bit of b. This saves alot of multiple precision shifting. + * The method is slightly modified to shift B unconditionally up to just under + * the leading bit of b. This saves a lot of multiple precision shifting. */ static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b) { diff --git a/src/tls/pkcs5.c b/src/tls/pkcs5.c index 4291b84..fd9e346 100644 --- a/src/tls/pkcs5.c +++ b/src/tls/pkcs5.c @@ -32,7 +32,7 @@ struct pkcs5_params { }; -enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid) +static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid) { if (oid->len == 7 && oid->oid[0] == 1 /* iso */ && diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c index 8b7e26f..d0da588 100644 --- a/src/tls/tlsv1_client.c +++ b/src/tls/tlsv1_client.c @@ -1,5 +1,5 @@ /* - * TLSv1 client (RFC 2246) + * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246) * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify @@ -67,7 +67,8 @@ int tls_derive_keys(struct tlsv1_client *conn, os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, TLS_RANDOM_LEN); - if (tls_prf(pre_master_secret, pre_master_secret_len, + if (tls_prf(conn->rl.tls_version, + pre_master_secret, pre_master_secret_len, "master secret", seed, 2 * TLS_RANDOM_LEN, conn->master_secret, TLS_MASTER_SECRET_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive " @@ -80,9 +81,11 @@ int tls_derive_keys(struct tlsv1_client *conn, os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); - key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len + - conn->rl.iv_size); - if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, + key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len); + if (conn->rl.tls_version == TLS_VERSION_1) + key_block_len += 2 * conn->rl.iv_size; + if (tls_prf(conn->rl.tls_version, + conn->master_secret, TLS_MASTER_SECRET_LEN, "key expansion", seed, 2 * TLS_RANDOM_LEN, key_block, key_block_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block"); @@ -107,12 +110,21 @@ int tls_derive_keys(struct tlsv1_client *conn, os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len); pos += conn->rl.key_material_len; - /* client_write_IV */ - os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size); - pos += conn->rl.iv_size; - /* server_write_IV */ - os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size); - pos += conn->rl.iv_size; + if (conn->rl.tls_version == TLS_VERSION_1) { + /* client_write_IV */ + os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size); + pos += conn->rl.iv_size; + /* server_write_IV */ + os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size); + pos += conn->rl.iv_size; + } else { + /* + * Use IV field to set the mask value for TLS v1.1. A fixed + * mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block + * Cipher option 2a. + */ + os_memset(conn->rl.write_iv, 0, conn->rl.iv_size); + } return 0; } @@ -126,17 +138,23 @@ int tls_derive_keys(struct tlsv1_client *conn, * @out_len: Length of the output buffer. * @appl_data: Pointer to application data pointer, or %NULL if dropped * @appl_data_len: Pointer to variable that is set to appl_data length + * @need_more_data: Set to 1 if more data would be needed to complete + * processing * Returns: Pointer to output data, %NULL on failure */ u8 * tlsv1_client_handshake(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, size_t *out_len, u8 **appl_data, - size_t *appl_data_len) + size_t *appl_data_len, int *need_more_data) { const u8 *pos, *end; - u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct; + u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct; size_t in_msg_len; int no_appl_data; + int used; + + if (need_more_data) + *need_more_data = 0; if (conn->state == CLIENT_HELLO) { if (in_len) @@ -144,6 +162,19 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn, return tls_send_client_hello(conn, out_len); } + if (conn->partial_input) { + if (wpabuf_resize(&conn->partial_input, in_len) < 0) { + wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " + "memory for pending record"); + tls_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + goto failed; + } + wpabuf_put_data(conn->partial_input, in_data, in_len); + in_data = wpabuf_head(conn->partial_input); + in_len = wpabuf_len(conn->partial_input); + } + if (in_data == NULL || in_len == 0) return NULL; @@ -156,13 +187,33 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn, /* Each received packet may include multiple records */ while (pos < end) { in_msg_len = in_len; - if (tlsv1_record_receive(&conn->rl, pos, end - pos, - in_msg, &in_msg_len, &alert)) { + used = tlsv1_record_receive(&conn->rl, pos, end - pos, + in_msg, &in_msg_len, &alert); + if (used < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Processing received " "record failed"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); goto failed; } + if (used == 0) { + struct wpabuf *partial; + wpa_printf(MSG_DEBUG, "TLSv1: Need more data"); + partial = wpabuf_alloc_copy(pos, end - pos); + wpabuf_free(conn->partial_input); + conn->partial_input = partial; + if (conn->partial_input == NULL) { + wpa_printf(MSG_DEBUG, "TLSv1: Failed to " + "allocate memory for pending " + "record"); + tls_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + goto failed; + } + os_free(in_msg); + if (need_more_data) + *need_more_data = 1; + return NULL; + } ct = pos[0]; in_pos = in_msg; @@ -180,7 +231,7 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn, in_pos += in_msg_len; } - pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); + pos += used; } os_free(in_msg); @@ -192,6 +243,8 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn, failed: os_free(in_msg); if (conn->alert_level) { + wpabuf_free(conn->partial_input); + conn->partial_input = NULL; conn->state = FAILED; os_free(msg); msg = tlsv1_client_send_alert(conn, conn->alert_level, @@ -202,6 +255,11 @@ failed: *out_len = 0; } + if (need_more_data == NULL || !(*need_more_data)) { + wpabuf_free(conn->partial_input); + conn->partial_input = NULL; + } + return msg; } @@ -227,10 +285,8 @@ int tlsv1_client_encrypt(struct tlsv1_client *conn, wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData", in_data, in_len); - os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len); - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA, - out_data, out_len, in_len, &rlen) < 0) { + out_data, out_len, in_data, in_len, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -246,58 +302,116 @@ int tlsv1_client_encrypt(struct tlsv1_client *conn, * @conn: TLSv1 client connection data from tlsv1_client_init() * @in_data: Pointer to input buffer (encrypted TLS data) * @in_len: Input buffer length - * @out_data: Pointer to output buffer (decrypted data from TLS tunnel) - * @out_len: Maximum out_data length - * Returns: Number of bytes written to out_data, -1 on failure + * @need_more_data: Set to 1 if more data would be needed to complete + * processing + * Returns: Decrypted data or %NULL on failure * * This function is used after TLS handshake has been completed successfully to * receive data from the encrypted tunnel. */ -int tlsv1_client_decrypt(struct tlsv1_client *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn, + const u8 *in_data, size_t in_len, + int *need_more_data) { const u8 *in_end, *pos; - int res; - u8 alert, *out_end, *out_pos; + int used; + u8 alert, *out_pos, ct; size_t olen; + struct wpabuf *buf = NULL; + + if (need_more_data) + *need_more_data = 0; + + if (conn->partial_input) { + if (wpabuf_resize(&conn->partial_input, in_len) < 0) { + wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " + "memory for pending record"); + alert = TLS_ALERT_INTERNAL_ERROR; + goto fail; + } + wpabuf_put_data(conn->partial_input, in_data, in_len); + in_data = wpabuf_head(conn->partial_input); + in_len = wpabuf_len(conn->partial_input); + } pos = in_data; in_end = in_data + in_len; - out_pos = out_data; - out_end = out_data + out_len; while (pos < in_end) { - if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type " - "0x%x", pos[0]); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; + ct = pos[0]; + if (wpabuf_resize(&buf, in_end - pos) < 0) { + alert = TLS_ALERT_INTERNAL_ERROR; + goto fail; } - - olen = out_end - out_pos; - res = tlsv1_record_receive(&conn->rl, pos, in_end - pos, - out_pos, &olen, &alert); - if (res < 0) { + out_pos = wpabuf_put(buf, 0); + olen = wpabuf_tailroom(buf); + used = tlsv1_record_receive(&conn->rl, pos, in_end - pos, + out_pos, &olen, &alert); + if (used < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing " "failed"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); - return -1; + goto fail; } - out_pos += olen; - if (out_pos > out_end) { - wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough " - "for processing the received record"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; + if (used == 0) { + struct wpabuf *partial; + wpa_printf(MSG_DEBUG, "TLSv1: Need more data"); + partial = wpabuf_alloc_copy(pos, in_end - pos); + wpabuf_free(conn->partial_input); + conn->partial_input = partial; + if (conn->partial_input == NULL) { + wpa_printf(MSG_DEBUG, "TLSv1: Failed to " + "allocate memory for pending " + "record"); + alert = TLS_ALERT_INTERNAL_ERROR; + goto fail; + } + if (need_more_data) + *need_more_data = 1; + return buf; } - pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); + if (ct == TLS_CONTENT_TYPE_ALERT) { + if (olen < 2) { + wpa_printf(MSG_DEBUG, "TLSv1: Alert " + "underflow"); + alert = TLS_ALERT_DECODE_ERROR; + goto fail; + } + wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", + out_pos[0], out_pos[1]); + if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) { + /* Continue processing */ + pos += used; + continue; + } + + alert = out_pos[1]; + goto fail; + } + + if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) { + wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type " + "0x%x when decrypting application data", + pos[0]); + alert = TLS_ALERT_UNEXPECTED_MESSAGE; + goto fail; + } + + wpabuf_put(buf, olen); + + pos += used; } - return out_pos - out_data; + wpabuf_free(conn->partial_input); + conn->partial_input = NULL; + return buf; + +fail: + wpabuf_free(buf); + wpabuf_free(conn->partial_input); + conn->partial_input = NULL; + tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); + return NULL; } @@ -352,14 +466,18 @@ struct tlsv1_client * tlsv1_client_init(void) count = 0; suites = conn->cipher_suites; #ifndef CONFIG_CRYPTO_INTERNAL + suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256; suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; #endif /* CONFIG_CRYPTO_INTERNAL */ + suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256; suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA; suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_MD5; conn->num_cipher_suites = count; + conn->rl.tls_version = TLS_VERSION; + return conn; } @@ -378,6 +496,7 @@ void tlsv1_client_deinit(struct tlsv1_client *conn) os_free(conn->client_hello_ext); tlsv1_client_free_dh(conn); tlsv1_cred_free(conn->cred); + wpabuf_free(conn->partial_input); os_free(conn); } @@ -421,7 +540,8 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, TLS_RANDOM_LEN); } - return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, + return tls_prf(conn->rl.tls_version, + conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed, 2 * TLS_RANDOM_LEN, out, out_len); } @@ -453,15 +573,24 @@ int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf, case TLS_RSA_WITH_3DES_EDE_CBC_SHA: cipher = "DES-CBC3-SHA"; break; + case TLS_DH_anon_WITH_AES_128_CBC_SHA256: + cipher = "ADH-AES-128-SHA256"; + break; case TLS_DH_anon_WITH_AES_128_CBC_SHA: cipher = "ADH-AES-128-SHA"; break; case TLS_RSA_WITH_AES_256_CBC_SHA: cipher = "AES-256-SHA"; break; + case TLS_RSA_WITH_AES_256_CBC_SHA256: + cipher = "AES-256-SHA256"; + break; case TLS_RSA_WITH_AES_128_CBC_SHA: cipher = "AES-128-SHA"; break; + case TLS_RSA_WITH_AES_128_CBC_SHA256: + cipher = "AES-128-SHA256"; + break; default: return -1; } @@ -613,8 +742,10 @@ int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers) count = 0; suites = conn->cipher_suites; #ifndef CONFIG_CRYPTO_INTERNAL + suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA256; suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA; #endif /* CONFIG_CRYPTO_INTERNAL */ + suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA256; suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA; suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5; diff --git a/src/tls/tlsv1_client.h b/src/tls/tlsv1_client.h index a620d62..ef5e694 100644 --- a/src/tls/tlsv1_client.h +++ b/src/tls/tlsv1_client.h @@ -1,5 +1,5 @@ /* - * TLSv1 client (RFC 2246) + * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246) * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify @@ -29,13 +29,13 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, u8 * tlsv1_client_handshake(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, size_t *out_len, u8 **appl_data, - size_t *appl_data_len); + size_t *appl_data_len, int *need_more_data); int tlsv1_client_encrypt(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, u8 *out_data, size_t out_len); -int tlsv1_client_decrypt(struct tlsv1_client *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len); +struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn, + const u8 *in_data, size_t in_len, + int *need_more_data); int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf, size_t buflen); int tlsv1_client_shutdown(struct tlsv1_client *conn); diff --git a/src/tls/tlsv1_client_i.h b/src/tls/tlsv1_client_i.h index f091bcf..92912ca 100644 --- a/src/tls/tlsv1_client_i.h +++ b/src/tls/tlsv1_client_i.h @@ -68,6 +68,8 @@ struct tlsv1_client { tlsv1_client_session_ticket_cb session_ticket_cb; void *session_ticket_cb_ctx; + + struct wpabuf *partial_input; }; diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index faa891a..eb0cbef 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -1,6 +1,6 @@ /* * TLSv1 client - read handshake message - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,6 +17,7 @@ #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" +#include "crypto/sha256.h" #include "crypto/tls.h" #include "x509v3.h" #include "tlsv1_common.h" @@ -38,6 +39,7 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct, const u8 *pos, *end; size_t left, len, i; u16 cipher_suite; + u16 tls_version; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " @@ -79,15 +81,20 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct, /* ProtocolVersion server_version */ if (end - pos < 2) goto decode_error; - if (WPA_GET_BE16(pos) != TLS_VERSION) { + tls_version = WPA_GET_BE16(pos); + if (!tls_version_ok(tls_version)) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " - "ServerHello"); + "ServerHello %u.%u", pos[0], pos[1]); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_PROTOCOL_VERSION); return -1; } pos += 2; + wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s", + tls_version_str(tls_version)); + conn->rl.tls_version = tls_version; + /* Random random */ if (end - pos < TLS_RANDOM_LEN) goto decode_error; @@ -816,6 +823,21 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", pos, TLS_VERIFY_DATA_LEN); +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version >= TLS_VERSION_1_2) { + hlen = SHA256_MAC_LEN; + if (conn->verify.sha256_server == NULL || + crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) + < 0) { + tls_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + conn->verify.sha256_server = NULL; + return -1; + } + conn->verify.sha256_server = NULL; + } else { +#endif /* CONFIG_TLSV12 */ + hlen = MD5_MAC_LEN; if (conn->verify.md5_server == NULL || crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { @@ -837,9 +859,15 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, return -1; } conn->verify.sha1_server = NULL; + hlen = MD5_MAC_LEN + SHA1_MAC_LEN; + +#ifdef CONFIG_TLSV12 + } +#endif /* CONFIG_TLSV12 */ - if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, - "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, + if (tls_prf(conn->rl.tls_version, + conn->master_secret, TLS_MASTER_SECRET_LEN, + "server finished", hash, hlen, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c index 0898df9..35a238b 100644 --- a/src/tls/tlsv1_client_write.c +++ b/src/tls/tlsv1_client_write.c @@ -1,6 +1,6 @@ /* * TLSv1 client - write handshake message - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,6 +17,7 @@ #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" +#include "crypto/sha256.h" #include "crypto/tls.h" #include "crypto/random.h" #include "x509v3.h" @@ -116,7 +117,8 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len) tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, out_len) < 0) { + rhdr, end - rhdr, hs_start, pos - hs_start, + out_len) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -192,7 +194,8 @@ static int tls_write_client_certificate(struct tlsv1_client *conn, WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { + rhdr, end - rhdr, hs_start, pos - hs_start, + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -413,7 +416,8 @@ static int tls_write_client_key_exchange(struct tlsv1_client *conn, WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { + rhdr, end - rhdr, hs_start, pos - hs_start, + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -433,7 +437,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn, { u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start; size_t rlen, hlen, clen; - u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos; + u8 hash[100], *hpos; enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; pos = *msgpos; @@ -473,6 +477,40 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn, hpos = hash; +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version == TLS_VERSION_1_2) { + hlen = SHA256_MAC_LEN; + if (conn->verify.sha256_cert == NULL || + crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < + 0) { + conn->verify.sha256_cert = NULL; + tls_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + conn->verify.sha256_cert = NULL; + + /* + * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5 + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithm, + * digest OCTET STRING + * } + * + * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11} + * + * DER encoded DigestInfo for SHA256 per RFC 3447: + * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || + * H + */ + os_memmove(hash + 19, hash, hlen); + hlen += 19; + os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65" + "\x03\x04\x02\x01\x05\x00\x04\x20", 19); + } else { +#endif /* CONFIG_TLSV12 */ + if (alg == SIGN_ALG_RSA) { hlen = MD5_MAC_LEN; if (conn->verify.md5_cert == NULL || @@ -503,8 +541,29 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn, if (alg == SIGN_ALG_RSA) hlen += MD5_MAC_LEN; +#ifdef CONFIG_TLSV12 + } +#endif /* CONFIG_TLSV12 */ + wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version >= TLS_VERSION_1_2) { + /* + * RFC 5246, 4.7: + * TLS v1.2 adds explicit indication of the used signature and + * hash algorithms. + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + */ + *pos++ = TLS_HASH_ALG_SHA256; + *pos++ = TLS_SIGN_ALG_RSA; + } +#endif /* CONFIG_TLSV12 */ + /* * RFC 2246, 4.7: * In digital signing, one-way hash functions are used as input for a @@ -534,7 +593,8 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn, WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { + rhdr, end - rhdr, hs_start, pos - hs_start, + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -553,17 +613,16 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn, static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { - u8 *pos, *rhdr; size_t rlen; - - pos = *msgpos; + u8 payload[1]; wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; - *pos = TLS_CHANGE_CIPHER_SPEC; + + payload[0] = TLS_CHANGE_CIPHER_SPEC; + if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, - rhdr, end - rhdr, 1, &rlen) < 0) { + *msgpos, end - *msgpos, payload, sizeof(payload), + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -578,7 +637,7 @@ static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn, return -1; } - *msgpos = rhdr + rlen; + *msgpos += rlen; return 0; } @@ -587,17 +646,30 @@ static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn, static int tls_write_client_finished(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { - u8 *pos, *rhdr, *hs_start, *hs_length; + u8 *pos, *hs_start; size_t rlen, hlen; - u8 verify_data[TLS_VERIFY_DATA_LEN]; + u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; - pos = *msgpos; - wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); /* Encrypted Handshake Message: Finished */ +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version >= TLS_VERSION_1_2) { + hlen = SHA256_MAC_LEN; + if (conn->verify.sha256_client == NULL || + crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) + < 0) { + tls_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + conn->verify.sha256_client = NULL; + return -1; + } + conn->verify.sha256_client = NULL; + } else { +#endif /* CONFIG_TLSV12 */ + hlen = MD5_MAC_LEN; if (conn->verify.md5_client == NULL || crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { @@ -619,43 +691,44 @@ static int tls_write_client_finished(struct tlsv1_client *conn, return -1; } conn->verify.sha1_client = NULL; + hlen = MD5_MAC_LEN + SHA1_MAC_LEN; + +#ifdef CONFIG_TLSV12 + } +#endif /* CONFIG_TLSV12 */ - if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, - "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, - verify_data, TLS_VERIFY_DATA_LEN)) { + if (tls_prf(conn->rl.tls_version, + conn->master_secret, TLS_MASTER_SECRET_LEN, + "client finished", hash, hlen, + verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", - verify_data, TLS_VERIFY_DATA_LEN); + verify_data + 1 + 3, TLS_VERIFY_DATA_LEN); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; /* Handshake */ - hs_start = pos; + pos = hs_start = verify_data; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; - /* uint24 length (to be filled) */ - hs_length = pos; + /* uint24 length */ + WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN); pos += 3; - os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN); - pos += TLS_VERIFY_DATA_LEN; - WPA_PUT_BE24(hs_length, pos - hs_length - 3); + pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { + *msgpos, end - *msgpos, hs_start, pos - hs_start, + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } - pos = rhdr + rlen; - - *msgpos = pos; + *msgpos += rlen; return 0; } @@ -778,7 +851,8 @@ u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, /* ContentType type */ *pos++ = TLS_CONTENT_TYPE_ALERT; /* ProtocolVersion version */ - WPA_PUT_BE16(pos, TLS_VERSION); + WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version : + TLS_VERSION); pos += 2; /* uint16 length (to be filled) */ length = pos; diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c index 2f9dd0f..871359a 100644 --- a/src/tls/tlsv1_common.c +++ b/src/tls/tlsv1_common.c @@ -1,6 +1,6 @@ /* * TLSv1 common routines - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -15,6 +15,8 @@ #include "includes.h" #include "common.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" #include "x509v3.h" #include "tlsv1_common.h" @@ -50,7 +52,15 @@ static const struct tls_cipher_suite tls_cipher_suites[] = { { TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }, { TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon, - TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA } + TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }, + { TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA, + TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 }, + { TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA, + TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }, + { TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon, + TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 }, + { TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon, + TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 } }; #define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0])) @@ -202,6 +212,19 @@ int tls_verify_hash_init(struct tls_verify_hash *verify) tls_verify_hash_free(verify); return -1; } +#ifdef CONFIG_TLSV12 + verify->sha256_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, + 0); + verify->sha256_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, + 0); + verify->sha256_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, + 0); + if (verify->sha256_client == NULL || verify->sha256_server == NULL || + verify->sha256_cert == NULL) { + tls_verify_hash_free(verify); + return -1; + } +#endif /* CONFIG_TLSV12 */ return 0; } @@ -221,6 +244,14 @@ void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf, crypto_hash_update(verify->md5_cert, buf, len); crypto_hash_update(verify->sha1_cert, buf, len); } +#ifdef CONFIG_TLSV12 + if (verify->sha256_client) + crypto_hash_update(verify->sha256_client, buf, len); + if (verify->sha256_server) + crypto_hash_update(verify->sha256_server, buf, len); + if (verify->sha256_cert) + crypto_hash_update(verify->sha256_cert, buf, len); +#endif /* CONFIG_TLSV12 */ } @@ -238,4 +269,60 @@ void tls_verify_hash_free(struct tls_verify_hash *verify) verify->sha1_client = NULL; verify->sha1_server = NULL; verify->sha1_cert = NULL; +#ifdef CONFIG_TLSV12 + crypto_hash_finish(verify->sha256_client, NULL, NULL); + crypto_hash_finish(verify->sha256_server, NULL, NULL); + crypto_hash_finish(verify->sha256_cert, NULL, NULL); + verify->sha256_client = NULL; + verify->sha256_server = NULL; + verify->sha256_cert = NULL; +#endif /* CONFIG_TLSV12 */ +} + + +int tls_version_ok(u16 ver) +{ + if (ver == TLS_VERSION_1) + return 1; +#ifdef CONFIG_TLSV11 + if (ver == TLS_VERSION_1_1) + return 1; +#endif /* CONFIG_TLSV11 */ +#ifdef CONFIG_TLSV12 + if (ver == TLS_VERSION_1_2) + return 1; +#endif /* CONFIG_TLSV12 */ + + return 0; +} + + +const char * tls_version_str(u16 ver) +{ + switch (ver) { + case TLS_VERSION_1: + return "1.0"; + case TLS_VERSION_1_1: + return "1.1"; + case TLS_VERSION_1_2: + return "1.2"; + } + + return "?"; +} + + +int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label, + const u8 *seed, size_t seed_len, u8 *out, size_t outlen) +{ +#ifdef CONFIG_TLSV12 + if (ver >= TLS_VERSION_1_2) { + tls_prf_sha256(secret, secret_len, label, seed, seed_len, + out, outlen); + return 0; + } +#endif /* CONFIG_TLSV12 */ + + return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out, + outlen); } diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h index 763a4af..027daa4 100644 --- a/src/tls/tlsv1_common.h +++ b/src/tls/tlsv1_common.h @@ -1,6 +1,6 @@ /* * TLSv1 common definitions - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,7 +17,18 @@ #include "crypto/crypto.h" -#define TLS_VERSION 0x0301 /* TLSv1 */ +#define TLS_VERSION_1 0x0301 /* TLSv1 */ +#define TLS_VERSION_1_1 0x0302 /* TLSv1.1 */ +#define TLS_VERSION_1_2 0x0303 /* TLSv1.2 */ +#ifdef CONFIG_TLSV12 +#define TLS_VERSION TLS_VERSION_1_2 +#else /* CONFIG_TLSV12 */ +#ifdef CONFIG_TLSV11 +#define TLS_VERSION TLS_VERSION_1_1 +#else /* CONFIG_TLSV11 */ +#define TLS_VERSION TLS_VERSION_1 +#endif /* CONFIG_TLSV11 */ +#endif /* CONFIG_TLSV12 */ #define TLS_RANDOM_LEN 32 #define TLS_PRE_MASTER_SECRET_LEN 48 #define TLS_MASTER_SECRET_LEN 48 @@ -82,10 +93,42 @@ enum { #define TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038 /* RFC 3268 */ #define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 /* RFC 3268 */ #define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A /* RFC 3268 */ +#define TLS_RSA_WITH_NULL_SHA256 0x003B /* RFC 5246 */ +#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C /* RFC 5246 */ +#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D /* RFC 5246 */ +#define TLS_DH_DSS_WITH_AES_128_CBC_SHA256 0x003E /* RFC 5246 */ +#define TLS_DH_RSA_WITH_AES_128_CBC_SHA256 0x003F /* RFC 5246 */ +#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 0x0040 /* RFC 5246 */ +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067 /* RFC 5246 */ +#define TLS_DH_DSS_WITH_AES_256_CBC_SHA256 0x0068 /* RFC 5246 */ +#define TLS_DH_RSA_WITH_AES_256_CBC_SHA256 0x0069 /* RFC 5246 */ +#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 0x006A /* RFC 5246 */ +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B /* RFC 5246 */ +#define TLS_DH_anon_WITH_AES_128_CBC_SHA256 0x006C /* RFC 5246 */ +#define TLS_DH_anon_WITH_AES_256_CBC_SHA256 0x006D /* RFC 5246 */ /* CompressionMethod */ #define TLS_COMPRESSION_NULL 0 +/* HashAlgorithm */ +enum { + TLS_HASH_ALG_NONE = 0, + TLS_HASH_ALG_MD5 = 1, + TLS_HASH_ALG_SHA1 = 2, + TLS_HASH_ALG_SHA224 = 3, + TLS_HASH_ALG_SHA256 = 4, + TLS_HASH_ALG_SHA384 = 5, + TLS_HASH_ALG_SHA512 = 6 +}; + +/* SignatureAlgorithm */ +enum { + TLS_SIGN_ALG_ANONYMOUS = 0, + TLS_SIGN_ALG_RSA = 1, + TLS_SIGN_ALG_DSA = 2, + TLS_SIGN_ALG_ECDSA = 3, +}; + /* AlertLevel */ #define TLS_ALERT_LEVEL_WARNING 1 #define TLS_ALERT_LEVEL_FATAL 2 @@ -169,7 +212,8 @@ typedef enum { typedef enum { TLS_HASH_NULL, TLS_HASH_MD5, - TLS_HASH_SHA + TLS_HASH_SHA, + TLS_HASH_SHA256 } tls_hash; struct tls_cipher_suite { @@ -197,10 +241,13 @@ struct tls_cipher_data { struct tls_verify_hash { struct crypto_hash *md5_client; struct crypto_hash *sha1_client; + struct crypto_hash *sha256_client; struct crypto_hash *md5_server; struct crypto_hash *sha1_server; + struct crypto_hash *sha256_server; struct crypto_hash *md5_cert; struct crypto_hash *sha1_cert; + struct crypto_hash *sha256_cert; }; @@ -212,5 +259,9 @@ int tls_verify_hash_init(struct tls_verify_hash *verify); void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf, size_t len); void tls_verify_hash_free(struct tls_verify_hash *verify); +int tls_version_ok(u16 ver); +const char * tls_version_str(u16 ver); +int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label, + const u8 *seed, size_t seed_len, u8 *out, size_t outlen); #endif /* TLSV1_COMMON_H */ diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c index aa467ef..d846480 100644 --- a/src/tls/tlsv1_cred.c +++ b/src/tls/tlsv1_cred.c @@ -46,7 +46,7 @@ void tlsv1_cred_free(struct tlsv1_credentials *cred) static int tlsv1_add_cert_der(struct x509_certificate **chain, const u8 *buf, size_t len) { - struct x509_certificate *cert; + struct x509_certificate *cert, *p; char name[128]; cert = x509_certificate_parse(buf, len); @@ -56,8 +56,20 @@ static int tlsv1_add_cert_der(struct x509_certificate **chain, return -1; } - cert->next = *chain; - *chain = cert; + p = *chain; + while (p && p->next) + p = p->next; + if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) { + /* + * The new certificate is the issuer of the last certificate in + * the chain - add the new certificate to the end. + */ + p->next = cert; + } else { + /* Add to the beginning of the chain */ + cert->next = *chain; + *chain = cert; + } x509_name_string(&cert->subject, name, sizeof(name)); wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name); @@ -232,10 +244,17 @@ static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len) if (!end) return NULL; } else { + const u8 *pos2; pos += os_strlen(pem_key_begin); end = search_tag(pem_key_end, pos, key + len - pos); if (!end) return NULL; + pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos); + if (pos2) { + wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key " + "format (Proc-Type/DEK-Info)"); + return NULL; + } } der = base64_decode(pos, end - pos, &der_len); diff --git a/src/tls/tlsv1_record.c b/src/tls/tlsv1_record.c index e811f0e..0314551 100644 --- a/src/tls/tlsv1_record.c +++ b/src/tls/tlsv1_record.c @@ -1,6 +1,6 @@ /* * TLSv1 Record Protocol - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,6 +17,7 @@ #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" +#include "crypto/sha256.h" #include "tlsv1_common.h" #include "tlsv1_record.h" @@ -52,6 +53,9 @@ int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl, } else if (suite->hash == TLS_HASH_SHA) { rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1; rl->hash_size = SHA1_MAC_LEN; + } else if (suite->hash == TLS_HASH_SHA256) { + rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA256; + rl->hash_size = SHA256_MAC_LEN; } data = tls_get_cipher_data(suite->cipher); @@ -138,10 +142,10 @@ int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl) * tlsv1_record_send - TLS record layer: Send a message * @rl: Pointer to TLS record layer data * @content_type: Content type (TLS_CONTENT_TYPE_*) - * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the - * beginning for record layer to fill in; payload filled in after this and - * extra space in the end for HMAC). + * @buf: Buffer for the generated TLS message (needs to have extra space for + * header, IV (TLS v1.1), and HMAC) * @buf_size: Maximum buf size + * @payload: Payload to be sent * @payload_len: Length of the payload * @out_len: Buffer for returning the used buf length * Returns: 0 on success, -1 on failure @@ -150,29 +154,62 @@ int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl) * the data using the current write cipher. */ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, - size_t buf_size, size_t payload_len, size_t *out_len) + size_t buf_size, const u8 *payload, size_t payload_len, + size_t *out_len) { - u8 *pos, *ct_start, *length, *payload; + u8 *pos, *ct_start, *length, *cpayload; struct crypto_hash *hmac; size_t clen; + int explicit_iv; pos = buf; + if (pos + TLS_RECORD_HEADER_LEN > buf + buf_size) + return -1; + /* ContentType type */ ct_start = pos; *pos++ = content_type; /* ProtocolVersion version */ - WPA_PUT_BE16(pos, TLS_VERSION); + WPA_PUT_BE16(pos, rl->tls_version); pos += 2; /* uint16 length */ length = pos; WPA_PUT_BE16(length, payload_len); pos += 2; - /* opaque fragment[TLSPlaintext.length] */ - payload = pos; + cpayload = pos; + explicit_iv = rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL && + rl->iv_size && rl->tls_version >= TLS_VERSION_1_1; + if (explicit_iv) { + /* opaque IV[Cipherspec.block_length] */ + if (pos + rl->iv_size > buf + buf_size) + return -1; + + /* + * Use random number R per the RFC 4346, 6.2.3.2 CBC Block + * Cipher option 2a. + */ + + if (os_get_random(pos, rl->iv_size)) + return -1; + pos += rl->iv_size; + } + + /* + * opaque fragment[TLSPlaintext.length] + * (opaque content[TLSCompressed.length] in GenericBlockCipher) + */ + if (pos + payload_len > buf + buf_size) + return -1; + os_memmove(pos, payload, payload_len); pos += payload_len; if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) { + /* + * MAC calculated over seq_num + TLSCompressed.type + + * TLSCompressed.version + TLSCompressed.length + + * TLSCompressed.fragment + */ hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret, rl->hash_size); if (hmac == NULL) { @@ -182,7 +219,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, } crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN); /* type + version + length + fragment */ - crypto_hash_update(hmac, ct_start, pos - ct_start); + crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN); + crypto_hash_update(hmac, payload, payload_len); clen = buf + buf_size - pos; if (clen < rl->hash_size) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not " @@ -200,7 +238,7 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, pos, clen); pos += clen; if (rl->iv_size) { - size_t len = pos - payload; + size_t len = pos - cpayload; size_t pad; pad = (len + 1) % rl->iv_size; if (pad) @@ -214,8 +252,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, pos += pad + 1; } - if (crypto_cipher_encrypt(rl->write_cbc, payload, - payload, pos - payload) < 0) + if (crypto_cipher_encrypt(rl->write_cbc, cpayload, + cpayload, pos - cpayload) < 0) return -1; } @@ -237,7 +275,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, * @out_len: Set to maximum out_data length by caller; used to return the * length of the used data * @alert: Buffer for returning an alert value on failure - * Returns: 0 on success, -1 on failure + * Returns: Number of bytes used from in_data on success, 0 if record was not + * complete (more data needed), or -1 on failure * * This function decrypts the received message, verifies HMAC and TLS record * layer header. @@ -250,40 +289,35 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, u8 padlen; struct crypto_hash *hmac; u8 len[2], hash[100]; - - wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received", - in_data, in_len); + int force_mac_error = 0; + u8 ct; if (in_len < TLS_RECORD_HEADER_LEN) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)", + wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu) - " + "need more data", (unsigned long) in_len); - *alert = TLS_ALERT_DECODE_ERROR; - return -1; + wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received", + in_data, in_len); + return 0; } + ct = in_data[0]; + rlen = WPA_GET_BE16(in_data + 3); wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d " - "length %d", in_data[0], in_data[1], in_data[2], - WPA_GET_BE16(in_data + 3)); - - if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE && - in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC && - in_data[0] != TLS_CONTENT_TYPE_ALERT && - in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x", - in_data[0]); - *alert = TLS_ALERT_UNEXPECTED_MESSAGE; - return -1; - } - - if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) { + "length %d", ct, in_data[1], in_data[2], (int) rlen); + + /* + * TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the + * protocol version in record layer. As such, accept any {03,xx} value + * to remain compatible with existing implementations. + */ + if (in_data[1] != 0x03) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version " - "%d.%d", in_data[1], in_data[2]); + "%u.%u", in_data[1], in_data[2]); *alert = TLS_ALERT_PROTOCOL_VERSION; return -1; } - rlen = WPA_GET_BE16(in_data + 3); - /* TLSCiphertext must not be more than 2^14+2048 bytes */ if (TLS_RECORD_HEADER_LEN + rlen > 18432) { wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", @@ -299,7 +333,19 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included " "(rlen=%lu > in_len=%lu)", (unsigned long) rlen, (unsigned long) in_len); - *alert = TLS_ALERT_DECODE_ERROR; + return 0; + } + + wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received", + in_data, rlen); + + if (ct != TLS_CONTENT_TYPE_HANDSHAKE && + ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC && + ct != TLS_CONTENT_TYPE_ALERT && + ct != TLS_CONTENT_TYPE_APPLICATION_DATA) { + wpa_printf(MSG_DEBUG, "TLSv1: Ignore record with unknown " + "content type 0x%x", ct); + *alert = TLS_ALERT_UNEXPECTED_MESSAGE; return -1; } @@ -312,58 +358,86 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, return -1; } - os_memcpy(out_data, in_data, in_len); - *out_len = in_len; - if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) { - if (crypto_cipher_decrypt(rl->read_cbc, out_data, + size_t plen; + if (crypto_cipher_decrypt(rl->read_cbc, in_data, out_data, in_len) < 0) { *alert = TLS_ALERT_DECRYPTION_FAILED; return -1; } + plen = in_len; + wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted " + "data", out_data, plen); + if (rl->iv_size) { - if (in_len == 0) { + /* + * TLS v1.0 defines different alert values for various + * failures. That may information to aid in attacks, so + * use the same bad_record_mac alert regardless of the + * issues. + * + * In addition, instead of returning immediately on + * error, run through the MAC check to make timing + * attacks more difficult. + */ + + if (rl->tls_version >= TLS_VERSION_1_1) { + /* Remove opaque IV[Cipherspec.block_length] */ + if (plen < rl->iv_size) { + wpa_printf(MSG_DEBUG, "TLSv1.1: Not " + "enough room for IV"); + force_mac_error = 1; + goto check_mac; + } + os_memmove(out_data, out_data + rl->iv_size, + plen - rl->iv_size); + plen -= rl->iv_size; + } + + /* Verify and remove padding */ + if (plen == 0) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record" " (no pad)"); - *alert = TLS_ALERT_DECODE_ERROR; - return -1; + force_mac_error = 1; + goto check_mac; } - padlen = out_data[in_len - 1]; - if (padlen >= in_len) { + padlen = out_data[plen - 1]; + if (padlen >= plen) { wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad " - "length (%u, in_len=%lu) in " + "length (%u, plen=%lu) in " "received record", - padlen, (unsigned long) in_len); - *alert = TLS_ALERT_DECRYPTION_FAILED; - return -1; + padlen, (unsigned long) plen); + force_mac_error = 1; + goto check_mac; } - for (i = in_len - padlen; i < in_len; i++) { + for (i = plen - padlen - 1; i < plen - 1; i++) { if (out_data[i] != padlen) { wpa_hexdump(MSG_DEBUG, "TLSv1: Invalid pad in " "received record", - out_data + in_len - padlen, - padlen); - *alert = TLS_ALERT_DECRYPTION_FAILED; - return -1; + out_data + plen - padlen - + 1, padlen + 1); + force_mac_error = 1; + goto check_mac; } } - *out_len -= padlen + 1; - } + plen -= padlen + 1; - wpa_hexdump(MSG_MSGDUMP, - "TLSv1: Record Layer - Decrypted data", - out_data, in_len); + wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - " + "Decrypted data with IV and padding " + "removed", out_data, plen); + } - if (*out_len < rl->hash_size) { + check_mac: + if (plen < rl->hash_size) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no " "hash value"); - *alert = TLS_ALERT_INTERNAL_ERROR; + *alert = TLS_ALERT_BAD_RECORD_MAC; return -1; } - *out_len -= rl->hash_size; + plen -= rl->hash_size; hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret, rl->hash_size); @@ -377,22 +451,30 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); /* type + version + length + fragment */ crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); - WPA_PUT_BE16(len, *out_len); + WPA_PUT_BE16(len, plen); crypto_hash_update(hmac, len, 2); - crypto_hash_update(hmac, out_data, *out_len); + crypto_hash_update(hmac, out_data, plen); hlen = sizeof(hash); if (crypto_hash_finish(hmac, hash, &hlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to calculate HMAC"); + *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } if (hlen != rl->hash_size || - os_memcmp(hash, out_data + *out_len, hlen) != 0) { + os_memcmp(hash, out_data + plen, hlen) != 0 || + force_mac_error) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in " - "received message"); + "received message (force_mac_error=%d)", + force_mac_error); *alert = TLS_ALERT_BAD_RECORD_MAC; return -1; } + + *out_len = plen; + } else { + os_memcpy(out_data, in_data, in_len); + *out_len = in_len; } /* TLSCompressed must not be more than 2^14+1024 bytes */ @@ -405,5 +487,5 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN); - return 0; + return TLS_RECORD_HEADER_LEN + rlen; } diff --git a/src/tls/tlsv1_record.h b/src/tls/tlsv1_record.h index 9c7c0a4..9eb9bfd 100644 --- a/src/tls/tlsv1_record.h +++ b/src/tls/tlsv1_record.h @@ -1,6 +1,6 @@ /* * TLSv1 Record Protocol - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,7 +17,7 @@ #include "crypto/crypto.h" -#define TLS_MAX_WRITE_MAC_SECRET_LEN 20 +#define TLS_MAX_WRITE_MAC_SECRET_LEN 32 #define TLS_MAX_WRITE_KEY_LEN 32 #define TLS_MAX_IV_LEN 16 #define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \ @@ -35,6 +35,8 @@ enum { }; struct tlsv1_record_layer { + u16 tls_version; + u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN]; u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN]; u8 write_key[TLS_MAX_WRITE_KEY_LEN]; @@ -66,7 +68,8 @@ int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl, int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl); int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl); int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, - size_t buf_size, size_t payload_len, size_t *out_len); + size_t buf_size, const u8 *payload, size_t payload_len, + size_t *out_len); int tlsv1_record_receive(struct tlsv1_record_layer *rl, const u8 *in_data, size_t in_len, u8 *out_data, size_t *out_len, u8 *alert); diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c index 6a61235..96e160c 100644 --- a/src/tls/tlsv1_server.c +++ b/src/tls/tlsv1_server.c @@ -1,6 +1,6 @@ /* - * TLSv1 server (RFC 2246) - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246) + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -49,7 +49,8 @@ int tlsv1_server_derive_keys(struct tlsv1_server *conn, os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, TLS_RANDOM_LEN); - if (tls_prf(pre_master_secret, pre_master_secret_len, + if (tls_prf(conn->rl.tls_version, + pre_master_secret, pre_master_secret_len, "master secret", seed, 2 * TLS_RANDOM_LEN, conn->master_secret, TLS_MASTER_SECRET_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive " @@ -64,7 +65,8 @@ int tlsv1_server_derive_keys(struct tlsv1_server *conn, os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len + conn->rl.iv_size); - if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, + if (tls_prf(conn->rl.tls_version, + conn->master_secret, TLS_MASTER_SECRET_LEN, "key expansion", seed, 2 * TLS_RANDOM_LEN, key_block, key_block_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block"); @@ -115,6 +117,7 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn, const u8 *pos, *end; u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct; size_t in_msg_len; + int used; if (in_data == NULL || in_len == 0) { wpa_printf(MSG_DEBUG, "TLSv1: No input data to server"); @@ -130,13 +133,21 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn, /* Each received packet may include multiple records */ while (pos < end) { in_msg_len = in_len; - if (tlsv1_record_receive(&conn->rl, pos, end - pos, - in_msg, &in_msg_len, &alert)) { + used = tlsv1_record_receive(&conn->rl, pos, end - pos, + in_msg, &in_msg_len, &alert); + if (used < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Processing received " "record failed"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); goto failed; } + if (used == 0) { + /* need more data */ + wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not " + "yet supported"); + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); + goto failed; + } ct = pos[0]; in_pos = in_msg; @@ -152,7 +163,7 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn, in_pos += in_msg_len; } - pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); + pos += used; } os_free(in_msg); @@ -201,10 +212,8 @@ int tlsv1_server_encrypt(struct tlsv1_server *conn, wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData", in_data, in_len); - os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len); - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA, - out_data, out_len, in_len, &rlen) < 0) { + out_data, out_len, in_data, in_len, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -232,8 +241,8 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn, u8 *out_data, size_t out_len) { const u8 *in_end, *pos; - int res; - u8 alert, *out_end, *out_pos; + int used; + u8 alert, *out_end, *out_pos, ct; size_t olen; pos = in_data; @@ -242,7 +251,46 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn, out_end = out_data + out_len; while (pos < in_end) { - if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { + ct = pos[0]; + olen = out_end - out_pos; + used = tlsv1_record_receive(&conn->rl, pos, in_end - pos, + out_pos, &olen, &alert); + if (used < 0) { + wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing " + "failed"); + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); + return -1; + } + if (used == 0) { + /* need more data */ + wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not " + "yet supported"); + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); + return -1; + } + + if (ct == TLS_CONTENT_TYPE_ALERT) { + if (olen < 2) { + wpa_printf(MSG_DEBUG, "TLSv1: Alert " + "underflow"); + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_DECODE_ERROR); + return -1; + } + wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", + out_pos[0], out_pos[1]); + if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) { + /* Continue processing */ + pos += used; + continue; + } + + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + out_pos[1]); + return -1; + } + + if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type " "0x%x", pos[0]); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, @@ -250,15 +298,6 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn, return -1; } - olen = out_end - out_pos; - res = tlsv1_record_receive(&conn->rl, pos, in_end - pos, - out_pos, &olen, &alert); - if (res < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing " - "failed"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); - return -1; - } out_pos += olen; if (out_pos > out_end) { wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough " @@ -268,7 +307,7 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn, return -1; } - pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); + pos += used; } return out_pos - out_data; @@ -412,7 +451,8 @@ int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, TLS_RANDOM_LEN); } - return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, + return tls_prf(conn->rl.tls_version, + conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed, 2 * TLS_RANDOM_LEN, out, out_len); } diff --git a/src/tls/tlsv1_server.h b/src/tls/tlsv1_server.h index 00c536c..daa4353 100644 --- a/src/tls/tlsv1_server.h +++ b/src/tls/tlsv1_server.h @@ -1,6 +1,6 @@ /* - * TLSv1 server (RFC 2246) - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246) + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c index fd74436..443c028 100644 --- a/src/tls/tlsv1_server_read.c +++ b/src/tls/tlsv1_server_read.c @@ -1,6 +1,6 @@ /* * TLSv1 server - read handshake message - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,6 +17,7 @@ #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" +#include "crypto/sha256.h" #include "crypto/tls.h" #include "x509v3.h" #include "tlsv1_common.h" @@ -85,15 +86,30 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct, conn->client_version = WPA_GET_BE16(pos); wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d", conn->client_version >> 8, conn->client_version & 0xff); - if (conn->client_version < TLS_VERSION) { + if (conn->client_version < TLS_VERSION_1) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " - "ClientHello"); + "ClientHello %u.%u", + conn->client_version >> 8, + conn->client_version & 0xff); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_PROTOCOL_VERSION); return -1; } pos += 2; + if (TLS_VERSION == TLS_VERSION_1) + conn->rl.tls_version = TLS_VERSION_1; +#ifdef CONFIG_TLSV12 + else if (conn->client_version >= TLS_VERSION_1_2) + conn->rl.tls_version = TLS_VERSION_1_2; +#endif /* CONFIG_TLSV12 */ + else if (conn->client_version > TLS_VERSION_1_1) + conn->rl.tls_version = TLS_VERSION_1_1; + else + conn->rl.tls_version = conn->client_version; + wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s", + tls_version_str(conn->rl.tls_version)); + /* Random random */ if (end - pos < TLS_RANDOM_LEN) goto decode_error; @@ -483,6 +499,14 @@ static int tls_process_client_key_exchange_rsa( encr_len = WPA_GET_BE16(pos); pos += 2; + if (pos + encr_len > end) { + wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange " + "format: encr_len=%u left=%u", + encr_len, (unsigned int) (end - pos)); + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_DECODE_ERROR); + return -1; + } outbuflen = outlen = end - pos; out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ? @@ -512,21 +536,21 @@ static int tls_process_client_key_exchange_rsa( */ if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key, - pos, end - pos, + pos, encr_len, out, &outlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt " - "PreMasterSecret (encr_len=%d outlen=%lu)", - (int) (end - pos), (unsigned long) outlen); + "PreMasterSecret (encr_len=%u outlen=%lu)", + encr_len, (unsigned long) outlen); use_random = 1; } - if (outlen != TLS_PRE_MASTER_SECRET_LEN) { + if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret " "length %lu", (unsigned long) outlen); use_random = 1; } - if (WPA_GET_BE16(out) != conn->client_version) { + if (!use_random && WPA_GET_BE16(out) != conn->client_version) { wpa_printf(MSG_DEBUG, "TLSv1: Client version in " "ClientKeyExchange does not match with version in " "ClientHello"); @@ -822,6 +846,47 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, hpos = hash; +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version == TLS_VERSION_1_2) { + /* + * RFC 5246, 4.7: + * TLS v1.2 adds explicit indication of the used signature and + * hash algorithms. + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + */ + if (end - pos < 2) { + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_DECODE_ERROR); + return -1; + } + if (pos[0] != TLS_HASH_ALG_SHA256 || + pos[1] != TLS_SIGN_ALG_RSA) { + wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/" + "signature(%u) algorithm", + pos[0], pos[1]); + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + pos += 2; + + hlen = SHA256_MAC_LEN; + if (conn->verify.sha256_cert == NULL || + crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < + 0) { + conn->verify.sha256_cert = NULL; + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + conn->verify.sha256_cert = NULL; + } else { +#endif /* CONFIG_TLSV12 */ + if (alg == SIGN_ALG_RSA) { hlen = MD5_MAC_LEN; if (conn->verify.md5_cert == NULL || @@ -852,6 +917,10 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, if (alg == SIGN_ALG_RSA) hlen += MD5_MAC_LEN; +#ifdef CONFIG_TLSV12 + } +#endif /* CONFIG_TLSV12 */ + wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); if (end - pos < 2) { @@ -891,6 +960,41 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature", buf, buflen); +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version >= TLS_VERSION_1_2) { + /* + * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5 + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithm, + * digest OCTET STRING + * } + * + * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11} + * + * DER encoded DigestInfo for SHA256 per RFC 3447: + * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || + * H + */ + if (buflen >= 19 + 32 && + os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01" + "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0) + { + wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = " + "SHA-256"); + os_memmove(buf, buf + 19, buflen - 19); + buflen -= 19; + } else { + wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized " + "DigestInfo"); + os_free(buf); + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_DECRYPT_ERROR); + return -1; + } + } +#endif /* CONFIG_TLSV12 */ + if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in " "CertificateVerify - did not match with calculated " @@ -1022,6 +1126,21 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", pos, TLS_VERIFY_DATA_LEN); +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version >= TLS_VERSION_1_2) { + hlen = SHA256_MAC_LEN; + if (conn->verify.sha256_client == NULL || + crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) + < 0) { + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + conn->verify.sha256_client = NULL; + return -1; + } + conn->verify.sha256_client = NULL; + } else { +#endif /* CONFIG_TLSV12 */ + hlen = MD5_MAC_LEN; if (conn->verify.md5_client == NULL || crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { @@ -1043,9 +1162,15 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, return -1; } conn->verify.sha1_client = NULL; + hlen = MD5_MAC_LEN + SHA1_MAC_LEN; + +#ifdef CONFIG_TLSV12 + } +#endif /* CONFIG_TLSV12 */ - if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, - "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, + if (tls_prf(conn->rl.tls_version, + conn->master_secret, TLS_MASTER_SECRET_LEN, + "client finished", hash, hlen, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c index e89e52e..0ca3b23 100644 --- a/src/tls/tlsv1_server_write.c +++ b/src/tls/tlsv1_server_write.c @@ -1,6 +1,6 @@ /* * TLSv1 server - write handshake message - * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,6 +17,7 @@ #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" +#include "crypto/sha256.h" #include "crypto/tls.h" #include "crypto/random.h" #include "x509v3.h" @@ -87,7 +88,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn, pos += 3; /* body - ServerHello */ /* ProtocolVersion server_version */ - WPA_PUT_BE16(pos, TLS_VERSION); + WPA_PUT_BE16(pos, conn->rl.tls_version); pos += 2; /* Random random: uint32 gmt_unix_time, opaque random_bytes */ os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN); @@ -143,7 +144,8 @@ static int tls_write_server_hello(struct tlsv1_server *conn, tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { + rhdr, end - rhdr, hs_start, pos - hs_start, + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -227,7 +229,8 @@ static int tls_write_server_certificate(struct tlsv1_server *conn, WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { + rhdr, end - rhdr, hs_start, pos - hs_start, + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -418,7 +421,8 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { + rhdr, end - rhdr, hs_start, pos - hs_start, + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -483,7 +487,8 @@ static int tls_write_server_certificate_request(struct tlsv1_server *conn, WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { + rhdr, end - rhdr, hs_start, pos - hs_start, + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -502,40 +507,35 @@ static int tls_write_server_certificate_request(struct tlsv1_server *conn, static int tls_write_server_hello_done(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { - u8 *pos, *rhdr, *hs_start, *hs_length; + u8 *pos; size_t rlen; - - pos = *msgpos; + u8 payload[4]; wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone"); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ - hs_start = pos; + pos = payload; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE; - /* uint24 length (to be filled) */ - hs_length = pos; + /* uint24 length */ + WPA_PUT_BE24(pos, 0); pos += 3; /* body - ServerHelloDone (empty) */ - WPA_PUT_BE24(hs_length, pos - hs_length - 3); - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { + *msgpos, end - *msgpos, payload, pos - payload, + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } - pos = rhdr + rlen; - tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); + tls_verify_hash_add(&conn->verify, payload, pos - payload); - *msgpos = pos; + *msgpos += rlen; return 0; } @@ -544,17 +544,16 @@ static int tls_write_server_hello_done(struct tlsv1_server *conn, static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { - u8 *pos, *rhdr; size_t rlen; - - pos = *msgpos; + u8 payload[1]; wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; - *pos = TLS_CHANGE_CIPHER_SPEC; + + payload[0] = TLS_CHANGE_CIPHER_SPEC; + if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, - rhdr, end - rhdr, 1, &rlen) < 0) { + *msgpos, end - *msgpos, payload, sizeof(payload), + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); @@ -569,7 +568,7 @@ static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn, return -1; } - *msgpos = rhdr + rlen; + *msgpos += rlen; return 0; } @@ -578,9 +577,9 @@ static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn, static int tls_write_server_finished(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { - u8 *pos, *rhdr, *hs_start, *hs_length; + u8 *pos, *hs_start; size_t rlen, hlen; - u8 verify_data[TLS_VERIFY_DATA_LEN]; + u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; pos = *msgpos; @@ -589,6 +588,21 @@ static int tls_write_server_finished(struct tlsv1_server *conn, /* Encrypted Handshake Message: Finished */ +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version >= TLS_VERSION_1_2) { + hlen = SHA256_MAC_LEN; + if (conn->verify.sha256_server == NULL || + crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) + < 0) { + conn->verify.sha256_server = NULL; + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + conn->verify.sha256_server = NULL; + } else { +#endif /* CONFIG_TLSV12 */ + hlen = MD5_MAC_LEN; if (conn->verify.md5_server == NULL || crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { @@ -610,43 +624,44 @@ static int tls_write_server_finished(struct tlsv1_server *conn, return -1; } conn->verify.sha1_server = NULL; + hlen = MD5_MAC_LEN + SHA1_MAC_LEN; + +#ifdef CONFIG_TLSV12 + } +#endif /* CONFIG_TLSV12 */ - if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, - "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, - verify_data, TLS_VERIFY_DATA_LEN)) { + if (tls_prf(conn->rl.tls_version, + conn->master_secret, TLS_MASTER_SECRET_LEN, + "server finished", hash, hlen, + verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", - verify_data, TLS_VERIFY_DATA_LEN); + verify_data + 1 + 3, TLS_VERIFY_DATA_LEN); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; /* Handshake */ - hs_start = pos; + pos = hs_start = verify_data; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; - /* uint24 length (to be filled) */ - hs_length = pos; + /* uint24 length */ + WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN); pos += 3; - os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN); pos += TLS_VERIFY_DATA_LEN; - WPA_PUT_BE24(hs_length, pos - hs_length - 3); tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { + *msgpos, end - *msgpos, hs_start, pos - hs_start, + &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } - pos = rhdr + rlen; - - *msgpos = pos; + *msgpos += rlen; return 0; } @@ -771,7 +786,8 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, /* ContentType type */ *pos++ = TLS_CONTENT_TYPE_ALERT; /* ProtocolVersion version */ - WPA_PUT_BE16(pos, TLS_VERSION); + WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version : + TLS_VERSION); pos += 2; /* uint16 length (to be filled) */ length = pos; diff --git a/src/utils/base64.c b/src/utils/base64.c index 155bfce..fb1224b 100644 --- a/src/utils/base64.c +++ b/src/utils/base64.c @@ -1,6 +1,6 @@ /* * Base64 encoding/decoding (RFC1341) - * Copyright (c) 2005, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -103,8 +103,9 @@ unsigned char * base64_encode(const unsigned char *src, size_t len, unsigned char * base64_decode(const unsigned char *src, size_t len, size_t *out_len) { - unsigned char dtable[256], *out, *pos, in[4], block[4], tmp; + unsigned char dtable[256], *out, *pos, block[4], tmp; size_t i, count, olen; + int pad = 0; os_memset(dtable, 0x80, 256); for (i = 0; i < sizeof(base64_table) - 1; i++) @@ -131,7 +132,8 @@ unsigned char * base64_decode(const unsigned char *src, size_t len, if (tmp == 0x80) continue; - in[count] = src[i]; + if (src[i] == '=') + pad++; block[count] = tmp; count++; if (count == 4) { @@ -139,16 +141,21 @@ unsigned char * base64_decode(const unsigned char *src, size_t len, *pos++ = (block[1] << 4) | (block[2] >> 2); *pos++ = (block[2] << 6) | block[3]; count = 0; + if (pad) { + if (pad == 1) + pos--; + else if (pad == 2) + pos -= 2; + else { + /* Invalid padding */ + os_free(out); + return NULL; + } + break; + } } } - if (pos > out) { - if (in[2] == '=') - pos -= 2; - else if (in[3] == '=') - pos--; - } - *out_len = pos - out; return out; } diff --git a/src/utils/edit.c b/src/utils/edit.c index 8f9e4ed..c5b17ac 100644 --- a/src/utils/edit.c +++ b/src/utils/edit.c @@ -1,6 +1,6 @@ /* * Command line editing and history - * Copyright (c) 2010, Jouni Malinen <j@w1.fi> + * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -24,6 +24,8 @@ static char cmdbuf[CMD_BUF_LEN]; static int cmdbuf_pos = 0; static int cmdbuf_len = 0; +static char currbuf[CMD_BUF_LEN]; +static int currbuf_valid = 0; #define HISTORY_MAX 100 @@ -231,18 +233,22 @@ static void history_prev(void) if (history_curr == dl_list_first(&history_list, struct edit_history, list)) { - cmdbuf[cmdbuf_len] = '\0'; - history_add(cmdbuf); + if (!currbuf_valid) { + cmdbuf[cmdbuf_len] = '\0'; + os_memcpy(currbuf, cmdbuf, cmdbuf_len + 1); + currbuf_valid = 1; + history_use(); + return; + } } - history_use(); - if (history_curr == dl_list_last(&history_list, struct edit_history, list)) return; history_curr = dl_list_entry(history_curr->list.next, struct edit_history, list); + history_use(); } @@ -250,8 +256,16 @@ static void history_next(void) { if (history_curr == NULL || history_curr == - dl_list_first(&history_list, struct edit_history, list)) + dl_list_first(&history_list, struct edit_history, list)) { + if (currbuf_valid) { + currbuf_valid = 0; + edit_clear_line(); + cmdbuf_len = cmdbuf_pos = os_strlen(currbuf); + os_memcpy(cmdbuf, currbuf, cmdbuf_len); + edit_redraw(); + } return; + } history_curr = dl_list_entry(history_curr->list.prev, struct edit_history, list); @@ -309,6 +323,8 @@ static void history_debug_dump(void) printf("\r"); dl_list_for_each_reverse(h, &history_list, struct edit_history, list) printf("%s%s\n", h == history_curr ? "[C]" : "", h->str); + if (currbuf_valid) + printf("{%s}\n", currbuf); edit_redraw(); } @@ -1104,6 +1120,7 @@ int edit_init(void (*cmd_cb)(void *ctx, char *cmd), char ** (*completion_cb)(void *ctx, const char *cmd, int pos), void *ctx, const char *history_file) { + currbuf[0] = '\0'; dl_list_init(&history_list); history_curr = NULL; if (history_file) diff --git a/src/utils/eloop.h b/src/utils/eloop.h index 1228f24..a656bf8 100644 --- a/src/utils/eloop.h +++ b/src/utils/eloop.h @@ -144,7 +144,7 @@ void eloop_unregister_sock(int sock, eloop_event_type type); * Returns: 0 on success, -1 on failure * * Register an event handler for the given event. This function is used to - * register eloop implementation specific events which are mainly targetted for + * register eloop implementation specific events which are mainly targeted for * operating system specific code (driver interface and l2_packet) since the * portable code will not be able to use such an OS-specific call. The handler * function will be called whenever the event is triggered. The handler diff --git a/src/utils/includes.h b/src/utils/includes.h index 63b5c23..cf2a42b 100644 --- a/src/utils/includes.h +++ b/src/utils/includes.h @@ -34,7 +34,6 @@ #include <errno.h> #endif /* _WIN32_WCE */ #include <ctype.h> -#include <time.h> #ifndef CONFIG_TI_COMPILER #ifndef _MSC_VER diff --git a/src/utils/list.h b/src/utils/list.h index ded7846..c8dccee 100644 --- a/src/utils/list.h +++ b/src/utils/list.h @@ -95,4 +95,7 @@ static inline unsigned int dl_list_len(struct dl_list *list) &item->member != (list); \ item = dl_list_entry(item->member.prev, type, member)) +#define DEFINE_DL_LIST(name) \ + struct dl_list name = { &(name), &(name) } + #endif /* LIST_H */ diff --git a/src/utils/os.h b/src/utils/os.h index f4723d8..f69478a 100644 --- a/src/utils/os.h +++ b/src/utils/os.h @@ -70,6 +70,16 @@ int os_get_time(struct os_time *t); int os_mktime(int year, int month, int day, int hour, int min, int sec, os_time_t *t); +struct os_tm { + int sec; /* 0..59 or 60 for leap seconds */ + int min; /* 0..59 */ + int hour; /* 0..23 */ + int day; /* 1..31 */ + int month; /* 1..12 */ + int year; /* Four digit year */ +}; + +int os_gmtime(os_time_t t, struct os_tm *tm); /** * os_daemonize - Run in the background (detach from the controlling terminal) diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c index 5260e23..8024a30 100644 --- a/src/utils/os_internal.c +++ b/src/utils/os_internal.c @@ -70,6 +70,24 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec, } +int os_gmtime(os_time_t t, struct os_tm *tm) +{ + struct tm *tm2; + time_t t2 = t; + + tm2 = gmtime(&t2); + if (tm2 == NULL) + return -1; + tm->sec = tm2->tm_sec; + tm->min = tm2->tm_min; + tm->hour = tm2->tm_hour; + tm->day = tm2->tm_mday; + tm->month = tm2->tm_mon + 1; + tm->year = tm2->tm_year + 1900; + return 0; +} + + int os_daemonize(const char *pid_file) { if (daemon(0, 0)) { diff --git a/src/utils/os_none.c b/src/utils/os_none.c index bab8f17..3fbb777 100644 --- a/src/utils/os_none.c +++ b/src/utils/os_none.c @@ -38,6 +38,11 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec, return -1; } +int os_gmtime(os_time_t t, struct os_tm *tm) +{ + return -1; +} + int os_daemonize(const char *pid_file) { diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c index 4e11758..9b16b33 100644 --- a/src/utils/os_unix.c +++ b/src/utils/os_unix.c @@ -14,6 +14,8 @@ #include "includes.h" +#include <time.h> + #ifdef ANDROID #include <linux/capability.h> #include <linux/prctl.h> @@ -25,9 +27,9 @@ #ifdef WPA_TRACE #include "common.h" -#include "list.h" #include "wpa_debug.h" #include "trace.h" +#include "list.h" static struct dl_list alloc_list; @@ -104,6 +106,24 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec, } +int os_gmtime(os_time_t t, struct os_tm *tm) +{ + struct tm *tm2; + time_t t2 = t; + + tm2 = gmtime(&t2); + if (tm2 == NULL) + return -1; + tm->sec = tm2->tm_sec; + tm->min = tm2->tm_min; + tm->hour = tm2->tm_hour; + tm->day = tm2->tm_mday; + tm->month = tm2->tm_mon + 1; + tm->year = tm2->tm_year + 1900; + return 0; +} + + #ifdef __APPLE__ #include <fcntl.h> static int os_daemon(int nochdir, int noclose) diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c index 0740964..51bd545 100644 --- a/src/utils/os_win32.c +++ b/src/utils/os_win32.c @@ -13,6 +13,7 @@ */ #include "includes.h" +#include <time.h> #include <winsock2.h> #include <wincrypt.h> @@ -92,6 +93,24 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec, } +int os_gmtime(os_time_t t, struct os_tm *tm) +{ + struct tm *tm2; + time_t t2 = t; + + tm2 = gmtime(&t2); + if (tm2 == NULL) + return -1; + tm->sec = tm2->tm_sec; + tm->min = tm2->tm_min; + tm->hour = tm2->tm_hour; + tm->day = tm2->tm_mday; + tm->month = tm2->tm_mon + 1; + tm->year = tm2->tm_year + 1900; + return 0; +} + + int os_daemonize(const char *pid_file) { /* TODO */ diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c index bf9f04a..c36193e 100644 --- a/src/utils/pcsc_funcs.c +++ b/src/utils/pcsc_funcs.c @@ -812,7 +812,7 @@ static int scard_get_record_len(struct scard_data *scard, unsigned char recnum, wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response", buf, blen); - if (blen < 2 || buf[0] != 0x6c) { + if (blen < 2 || (buf[0] != 0x6c && buf[0] != 0x67)) { wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file " "length determination"); return -1; diff --git a/src/utils/radiotap.h b/src/utils/radiotap.h index 508264c..137288f 100644 --- a/src/utils/radiotap.h +++ b/src/utils/radiotap.h @@ -238,5 +238,6 @@ enum ieee80211_radiotap_type { * retries */ #define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ +#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ACK */ #endif /* IEEE80211_RADIOTAP_H */ diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c index 0588fc6..5b56d83 100644 --- a/src/utils/wpa_debug.c +++ b/src/utils/wpa_debug.c @@ -34,7 +34,7 @@ int wpa_debug_timestamp = 0; #ifndef ANDROID_LOG_NAME #define ANDROID_LOG_NAME "wpa_supplicant" -#endif +#endif /* ANDROID_LOG_NAME */ void android_printf(int level, char *format, ...) { diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h index ae36afe..64ada57 100644 --- a/src/utils/wpa_debug.h +++ b/src/utils/wpa_debug.h @@ -136,7 +136,7 @@ void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); static inline void wpa_hexdump_buf_key(int level, const char *title, const struct wpabuf *buf) { - wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : 0, + wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL, buf ? wpabuf_len(buf) : 0); } diff --git a/src/wps/upnp_xml.c b/src/wps/upnp_xml.c index b1b1e2b..a9958ee 100644 --- a/src/wps/upnp_xml.c +++ b/src/wps/upnp_xml.c @@ -75,8 +75,8 @@ * Note that angle brackets present in the original data must have been encoded * as < and > so they will not trouble us. */ -static int xml_next_tag(const char *in, const char **out, - const char **out_tagname, const char **end) +int xml_next_tag(const char *in, const char **out, + const char **out_tagname, const char **end) { while (*in && *in != '<') in++; diff --git a/src/wps/upnp_xml.h b/src/wps/upnp_xml.h index 62dbe60..616af3d 100644 --- a/src/wps/upnp_xml.h +++ b/src/wps/upnp_xml.h @@ -16,6 +16,8 @@ void xml_data_encode(struct wpabuf *buf, const char *data, int len); void xml_add_tagged_data(struct wpabuf *buf, const char *tag, const char *data); +int xml_next_tag(const char *in, const char **out, + const char **out_tagname, const char **end); char * xml_get_first_item(const char *doc, const char *item); struct wpabuf * xml_get_base64_item(const char *data, const char *name, enum http_reply_code *ret); diff --git a/src/wps/wps.c b/src/wps/wps.c index 5c8c25f..2ba3d4b 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -67,12 +67,11 @@ struct wps_data * wps_init(const struct wps_config *cfg) /* Use special PIN '00000000' for PBC */ data->dev_pw_id = DEV_PW_PUSHBUTTON; os_free(data->dev_password); - data->dev_password = os_malloc(8); + data->dev_password = (u8 *) os_strdup("00000000"); if (data->dev_password == NULL) { os_free(data); return NULL; } - os_memset(data->dev_password, '0', 8); data->dev_password_len = 8; } @@ -355,6 +354,19 @@ const u8 * wps_get_uuid_e(const struct wpabuf *msg) /** + * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0 + */ +int wps_is_20(const struct wpabuf *msg) +{ + struct wps_parse_attr attr; + + if (msg == NULL || wps_parse_msg(msg, &attr) < 0) + return 0; + return attr.version2 != NULL; +} + + +/** * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request * @req_type: Value for Request Type attribute * Returns: WPS IE or %NULL on failure @@ -443,7 +455,6 @@ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, const u8 *req_dev_types) { struct wpabuf *ie; - u16 methods = 0; wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); @@ -451,35 +462,9 @@ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, if (ie == NULL) return NULL; - methods |= WPS_CONFIG_PUSHBUTTON; -#ifdef CONFIG_WPS2 - /* - * TODO: Should figure out whether this device has a physical or - * virtual pushbutton. - */ - methods |= WPS_CONFIG_VIRT_PUSHBUTTON; -#endif /* CONFIG_WPS2 */ - - /* - * TODO: Should figure out whether this Probe Request was triggered - * using physical or virtual display. Also, if the device has a PIN on - * a label, that should be indicated here. - */ - methods |= WPS_CONFIG_DISPLAY | -#ifdef CONFIG_WPS2 - WPS_CONFIG_VIRT_DISPLAY | -#endif /* CONFIG_WPS2 */ - WPS_CONFIG_KEYPAD; -#ifdef CONFIG_WPS_UFD - methods |= WPS_CONFIG_USBA; -#endif /* CONFIG_WPS_UFD */ -#ifdef CONFIG_WPS_NFC - methods |= WPS_CONFIG_NFC_INTERFACE; -#endif /* CONFIG_WPS_NFC */ - if (wps_build_version(ie) || wps_build_req_type(ie, req_type) || - wps_build_config_methods(ie, methods) || + wps_build_config_methods(ie, dev->config_methods) || wps_build_uuid_e(ie, uuid) || wps_build_primary_dev_type(dev, ie) || wps_build_rf_bands(dev, ie) || diff --git a/src/wps/wps.h b/src/wps/wps.h index 3e4c218..4986881 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -99,6 +99,7 @@ struct wps_device_data { u8 num_sec_dev_types; u32 os_version; u8 rf_bands; + u16 config_methods; struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; int p2p; @@ -239,6 +240,7 @@ int wps_ap_priority_compar(const struct wpabuf *wps_a, int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, int ver1_compat); const u8 * wps_get_uuid_e(const struct wpabuf *msg); +int wps_is_20(const struct wpabuf *msg); struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type); struct wpabuf * wps_build_assoc_resp_ie(void); @@ -782,6 +784,7 @@ int wps_registrar_wps_cancel(struct wps_registrar *reg); int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid); int wps_registrar_button_pushed(struct wps_registrar *reg, const u8 *p2p_dev_addr); +void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e); void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, const struct wpabuf *wps_data, int p2p_wildcard); @@ -791,6 +794,9 @@ int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr, int wps_registrar_config_ap(struct wps_registrar *reg, struct wps_credential *cred); +int wps_build_credential_wrap(struct wpabuf *msg, + const struct wps_credential *cred); + unsigned int wps_pin_checksum(unsigned int pin); unsigned int wps_pin_valid(unsigned int pin); unsigned int wps_generate_pin(void); diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c index 7b462d3..55b5573 100644 --- a/src/wps/wps_attr_parse.c +++ b/src/wps/wps_attr_parse.c @@ -557,7 +557,9 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr) { const u8 *pos, *end; u16 type, len; +#ifdef WPS_WORKAROUNDS u16 prev_type = 0; +#endif /* WPS_WORKAROUNDS */ os_memset(attr, 0, sizeof(*attr)); pos = wpabuf_head(msg); @@ -622,7 +624,9 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr) if (wps_set_attr(attr, type, pos, len) < 0) return -1; +#ifdef WPS_WORKAROUNDS prev_type = type; +#endif /* WPS_WORKAROUNDS */ pos += len; } diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c index 5d0508c..505837b 100644 --- a/src/wps/wps_common.c +++ b/src/wps/wps_common.c @@ -22,7 +22,6 @@ #include "crypto/sha256.h" #include "crypto/random.h" #include "wps_i.h" -#include "wps_dev_attr.h" void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index 5b3c045..0fbaa3f 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -967,7 +967,7 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps, return WPS_CONTINUE; } - if (wps_validate_m4_encr(decrypted, attr->version2 != 0) < 0) { + if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) { wpabuf_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; @@ -1020,7 +1020,7 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps, return WPS_CONTINUE; } - if (wps_validate_m6_encr(decrypted, attr->version2 != 0) < 0) { + if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) { wpabuf_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; @@ -1086,8 +1086,8 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps, return WPS_CONTINUE; } - if (wps_validate_m8_encr(decrypted, wps->wps->ap, attr->version2 != 0) - < 0) { + if (wps_validate_m8_encr(decrypted, wps->wps->ap, + attr->version2 != NULL) < 0) { wpabuf_free(decrypted); wps->state = SEND_WSC_NACK; return WPS_CONTINUE; diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index a461836..856e9fb 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -502,16 +502,61 @@ static void wps_er_get_device_info(struct wps_er_ap *ap) } +static const char * wps_er_find_wfadevice(const char *data) +{ + const char *tag, *tagname, *end; + char *val; + int found = 0; + + while (!found) { + /* Find next <device> */ + for (;;) { + if (xml_next_tag(data, &tag, &tagname, &end)) + return NULL; + data = end; + if (!os_strncasecmp(tagname, "device", 6) && + *tag != '/' && + (tagname[6] == '>' || !isgraph(tagname[6]))) { + break; + } + } + + /* Check whether deviceType is WFADevice */ + val = xml_get_first_item(data, "deviceType"); + if (val == NULL) + return NULL; + wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val); + found = os_strcasecmp(val, "urn:schemas-wifialliance-org:" + "device:WFADevice:1") == 0; + os_free(val); + } + + return data; +} + + static void wps_er_parse_device_description(struct wps_er_ap *ap, struct wpabuf *reply) { /* Note: reply includes null termination after the buffer data */ - const char *data = wpabuf_head(reply); + const char *tmp, *data = wpabuf_head(reply); char *pos; wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info", wpabuf_head(reply), wpabuf_len(reply)); + /* + * The root device description may include multiple devices, so first + * find the beginning of the WFADevice description to allow the + * simplistic parser to pick the correct entries. + */ + tmp = wps_er_find_wfadevice(data); + if (tmp == NULL) { + wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - " + "trying to parse invalid data"); + } else + data = tmp; + ap->friendly_name = xml_get_first_item(data, "friendlyName"); wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 65ff40d..eda1c70 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -310,13 +310,17 @@ static void wps_registrar_add_pbc_session(struct wps_registrar *reg, static void wps_registrar_remove_pbc_session(struct wps_registrar *reg, - const u8 *uuid_e) + const u8 *uuid_e, + const u8 *p2p_dev_addr) { struct wps_pbc_session *pbc, *prev = NULL, *tmp; pbc = reg->pbc_sessions; while (pbc) { - if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) { + if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 || + (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) && + os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) == + 0)) { if (prev) prev->next = pbc->next; else @@ -485,10 +489,8 @@ static void wps_set_pushbutton(u16 *methods, u16 conf_methods) *methods |= WPS_CONFIG_VIRT_PUSHBUTTON; if (conf_methods & WPS_CONFIG_PHY_PUSHBUTTON) *methods |= WPS_CONFIG_PHY_PUSHBUTTON; - if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) != - WPS_CONFIG_VIRT_PUSHBUTTON || - (*methods & WPS_CONFIG_PHY_PUSHBUTTON) != - WPS_CONFIG_PHY_PUSHBUTTON) { + if (!(*methods & (WPS_CONFIG_VIRT_PUSHBUTTON | + WPS_CONFIG_PHY_PUSHBUTTON))) { /* * Required to include virtual/physical flag, but we were not * configured with push button type, so have to default to one @@ -549,15 +551,7 @@ static int wps_build_probe_config_methods(struct wps_registrar *reg, static int wps_build_config_methods_r(struct wps_registrar *reg, struct wpabuf *msg) { - u16 methods; - methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; -#ifdef CONFIG_WPS2 - methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | - WPS_CONFIG_PHY_PUSHBUTTON); -#endif /* CONFIG_WPS2 */ - if (reg->pbc) - wps_set_pushbutton(&methods, reg->wps->config_methods); - return wps_build_config_methods(msg, methods); + return wps_build_config_methods(msg, reg->wps->config_methods); } @@ -901,8 +895,8 @@ static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx) * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout * or when a PBC registration is completed. If more than one Enrollee in active * PBC mode has been detected during the monitor time (previous 2 minutes), the - * PBC mode is not actived and -2 is returned to indicate session overlap. This - * is skipped if a specific Enrollee is selected. + * PBC mode is not activated and -2 is returned to indicate session overlap. + * This is skipped if a specific Enrollee is selected. */ int wps_registrar_button_pushed(struct wps_registrar *reg, const u8 *p2p_dev_addr) @@ -951,6 +945,18 @@ static void wps_registrar_pin_completed(struct wps_registrar *reg) } +void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e) +{ + if (registrar->pbc) { + wps_registrar_remove_pbc_session(registrar, + uuid_e, NULL); + wps_registrar_pbc_completed(registrar); + } else { + wps_registrar_pin_completed(registrar); + } +} + + int wps_registrar_wps_cancel(struct wps_registrar *reg) { if (reg->pbc) { @@ -1420,6 +1426,25 @@ static int wps_build_credential(struct wpabuf *msg, } +int wps_build_credential_wrap(struct wpabuf *msg, + const struct wps_credential *cred) +{ + struct wpabuf *wbuf; + wbuf = wpabuf_alloc(200); + if (wbuf == NULL) + return -1; + if (wps_build_credential(wbuf, cred)) { + wpabuf_free(wbuf); + return -1; + } + wpabuf_put_be16(msg, ATTR_CRED); + wpabuf_put_be16(msg, wpabuf_len(wbuf)); + wpabuf_put_buf(msg, wbuf); + wpabuf_free(wbuf); + return 0; +} + + int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) { struct wpabuf *cred; @@ -1593,6 +1618,35 @@ static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg) } +static struct wpabuf * wps_build_ap_cred(struct wps_data *wps) +{ + struct wpabuf *msg, *plain; + + msg = wpabuf_alloc(1000); + if (msg == NULL) + return NULL; + + plain = wpabuf_alloc(200); + if (plain == NULL) { + wpabuf_free(msg); + return NULL; + } + + if (wps_build_ap_settings(wps, plain)) { + wpabuf_free(plain); + wpabuf_free(msg); + return NULL; + } + + wpabuf_put_be16(msg, ATTR_CRED); + wpabuf_put_be16(msg, wpabuf_len(plain)); + wpabuf_put_buf(msg, plain); + wpabuf_free(plain); + + return msg; +} + + static struct wpabuf * wps_build_m2(struct wps_data *wps) { struct wpabuf *msg; @@ -2551,6 +2605,8 @@ static void wps_cred_update(struct wps_credential *dst, static int wps_process_ap_settings_r(struct wps_data *wps, struct wps_parse_attr *attr) { + struct wpabuf *msg; + if (wps->wps->ap || wps->er) return 0; @@ -2577,12 +2633,24 @@ static int wps_process_ap_settings_r(struct wps_data *wps, */ wps_registrar_pin_completed(wps->wps->registrar); + msg = wps_build_ap_cred(wps); + if (msg == NULL) + return -1; + wps->cred.cred_attr = wpabuf_head(msg); + wps->cred.cred_attr_len = wpabuf_len(msg); + if (wps->ap_settings_cb) { wps->ap_settings_cb(wps->ap_settings_cb_ctx, &wps->cred); + wpabuf_free(msg); return 1; } wps_sta_cred_cb(wps); + + wps->cred.cred_attr = NULL; + wps->cred.cred_attr_len = 0; + wpabuf_free(msg); + return 1; } } @@ -2983,7 +3051,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps, if (wps->pbc) { wps_registrar_remove_pbc_session(wps->wps->registrar, - wps->uuid_e); + wps->uuid_e, + wps->p2p_dev_addr); wps_registrar_pbc_completed(wps->wps->registrar); } else { wps_registrar_pin_completed(wps->wps->registrar); diff --git a/src/wps/wps_ufd.c b/src/wps/wps_ufd.c index 1a911e1..61f6553 100644 --- a/src/wps/wps_ufd.c +++ b/src/wps/wps_ufd.c @@ -16,7 +16,6 @@ #include "common.h" #include <sys/types.h> #include <sys/stat.h> -#include <sys/wait.h> #include <fcntl.h> #include <dirent.h> diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c index 763dcaf..06dcd20 100644 --- a/src/wps/wps_upnp.c +++ b/src/wps/wps_upnp.c @@ -47,7 +47,7 @@ * -- Needs renaming with module prefix to avoid polluting the debugger * namespace and causing possible collisions with other static fncs * and structure declarations when using the debugger. - * -- The http error code generation is pretty bogus, hopefully noone cares. + * -- The http error code generation is pretty bogus, hopefully no one cares. * * Author: Ted Merrill, Atheros Communications, based upon earlier work * as explained above and below. @@ -172,7 +172,7 @@ #include "includes.h" -#include <assert.h> +#include <time.h> #include <net/if.h> #include <netdb.h> #include <sys/ioctl.h> diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c index c7fb158..4c4aebf 100644 --- a/src/wps/wps_upnp_ssdp.c +++ b/src/wps/wps_upnp_ssdp.c @@ -97,16 +97,6 @@ static int line_length(const char *l) } -/* No. of chars excluding trailing whitespace */ -static int line_length_stripped(const char *l) -{ - const char *lp = l + line_length(l); - while (lp > l && !isgraph(lp[-1])) - lp--; - return lp - l; -} - - static int str_starts(const char *str, const char *start) { return os_strncmp(str, start, os_strlen(start)) == 0; @@ -530,7 +520,6 @@ static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm, #ifndef CONFIG_NO_STDOUT_DEBUG const char *start = data; #endif /* CONFIG_NO_STDOUT_DEBUG */ - const char *end; int got_host = 0; int got_st = 0, st_match = 0; int got_man = 0; @@ -545,7 +534,6 @@ static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm, /* Parse remaining lines */ for (; *data != '\0'; data += line_length(data)) { - end = data + line_length_stripped(data); if (token_eq(data, "host")) { /* The host line indicates who the packet * is addressed to... but do we really care? diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c index 917f60b..ce0bede 100644 --- a/src/wps/wps_upnp_web.c +++ b/src/wps/wps_upnp_web.c @@ -956,7 +956,7 @@ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm, break; /* no unterminated lines allowed */ /* NT assures that it is our type of subscription; - * not used for a renewl. + * not used for a renewal. **/ match = "NT:"; match_len = os_strlen(match); |