From c5cf0a18f1ac9caac20966f17be20c6e0892daa1 Mon Sep 17 00:00:00 2001 From: Chao-Wen Yang Date: Thu, 13 Jan 2011 17:50:59 +0200 Subject: [PATCH] WPS: Add mechanism for indicating non-standard WPS errors Previously, only the Configuration Error values were indicated in WPS-FAIL events. Since those values are defined in the specification it is not feasible to extend them for indicating other errors. Add a new error indication value that is internal to wpa_supplicant and hostapd to allow other errors to be indicated. Use the new mechanism to indicate if negotiation fails because of WEP or TKIP-only configurations being disallows by WPS 2.0. --- src/ap/wps_hostapd.c | 20 +++++++++++++++++--- src/wps/wps.h | 1 + src/wps/wps_common.c | 3 ++- src/wps/wps_defs.h | 8 ++++++++ src/wps/wps_enrollee.c | 22 ++++++++++++++++------ src/wps/wps_i.h | 3 ++- src/wps/wps_registrar.c | 24 ++++++++++++++++-------- wpa_supplicant/wps_supplicant.c | 31 ++++++++++++++++++++++++++----- 8 files changed, 88 insertions(+), 24 deletions(-) diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index b5cd5a847..cfff55cdf 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -535,12 +535,26 @@ static void hostapd_pwd_auth_fail(struct hostapd_data *hapd, } +static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = { + "No Error", /* WPS_EI_NO_ERROR */ + "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */ + "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */ +}; + static void hostapd_wps_event_fail(struct hostapd_data *hapd, struct wps_event_fail *fail) { - wpa_msg(hapd->msg_ctx, MSG_INFO, - WPS_EVENT_FAIL "msg=%d config_error=%d", - fail->msg, fail->config_error); + if (fail->error_indication > 0 && + fail->error_indication < NUM_WPS_EI_VALUES) { + wpa_msg(hapd->msg_ctx, MSG_INFO, + WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", + fail->msg, fail->config_error, fail->error_indication, + wps_event_fail_reason[fail->error_indication]); + } else { + wpa_msg(hapd->msg_ctx, MSG_INFO, + WPS_EVENT_FAIL "msg=%d config_error=%d", + fail->msg, fail->config_error); + } } diff --git a/src/wps/wps.h b/src/wps/wps.h index ce0a22634..771551a85 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -456,6 +456,7 @@ union wps_event_data { struct wps_event_fail { int msg; u16 config_error; + u16 error_indication; } fail; struct wps_event_pwd_auth_fail { diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c index 59fbca7c4..5d0508cf1 100644 --- a/src/wps/wps_common.c +++ b/src/wps/wps_common.c @@ -257,7 +257,7 @@ unsigned int wps_generate_pin(void) void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg, - u16 config_error) + u16 config_error, u16 error_indication) { union wps_event_data data; @@ -267,6 +267,7 @@ void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg, os_memset(&data, 0, sizeof(data)); data.fail.msg = msg; data.fail.config_error = config_error; + data.fail.error_indication = error_indication; wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data); } diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h index 868f8ad7e..43311f30d 100644 --- a/src/wps/wps_defs.h +++ b/src/wps/wps_defs.h @@ -224,6 +224,14 @@ enum wps_config_error { WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18 }; +/* Vendor specific Error Indication for WPS event messages */ +enum wps_error_indication { + WPS_EI_NO_ERROR, + WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED, + WPS_EI_SECURITY_WEP_PROHIBITED, + NUM_WPS_EI_VALUES +}; + /* RF Bands */ #define WPS_RF_24GHZ 0x01 #define WPS_RF_50GHZ 0x02 diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index fcd619757..390254e43 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -672,6 +672,7 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred, if (wps->cred.encr_type & WPS_ENCR_WEP) { wpa_printf(MSG_INFO, "WPS: Reject Credential " "due to WEP configuration"); + wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED; return -2; } @@ -772,6 +773,7 @@ static int wps_process_ap_settings_e(struct wps_data *wps, if (cred.encr_type & WPS_ENCR_WEP) { wpa_printf(MSG_INFO, "WPS: Reject new AP settings " "due to WEP configuration"); + wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED; return -1; } @@ -789,6 +791,8 @@ static int wps_process_ap_settings_e(struct wps_data *wps, WPS_AUTH_WPAPSK) { wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC 2.0 " "AP Settings: WPA-Personal/TKIP only"); + wps->error_indication = + WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED; return -1; } } @@ -1140,21 +1144,24 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps, return WPS_FAILURE; ret = wps_process_m4(wps, msg, &attr); if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) - wps_fail_event(wps->wps, WPS_M4, wps->config_error); + wps_fail_event(wps->wps, WPS_M4, wps->config_error, + wps->error_indication); break; case WPS_M6: if (wps_validate_m6(msg) < 0) return WPS_FAILURE; ret = wps_process_m6(wps, msg, &attr); if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) - wps_fail_event(wps->wps, WPS_M6, wps->config_error); + wps_fail_event(wps->wps, WPS_M6, wps->config_error, + wps->error_indication); break; case WPS_M8: if (wps_validate_m8(msg) < 0) return WPS_FAILURE; ret = wps_process_m8(wps, msg, &attr); if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) - wps_fail_event(wps->wps, WPS_M8, wps->config_error); + wps_fail_event(wps->wps, WPS_M8, wps->config_error, + wps->error_indication); break; default: wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d", @@ -1281,13 +1288,16 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps, switch (wps->state) { case RECV_M4: - wps_fail_event(wps->wps, WPS_M3, config_error); + wps_fail_event(wps->wps, WPS_M3, config_error, + wps->error_indication); break; case RECV_M6: - wps_fail_event(wps->wps, WPS_M5, config_error); + wps_fail_event(wps->wps, WPS_M5, config_error, + wps->error_indication); break; case RECV_M8: - wps_fail_event(wps->wps, WPS_M7, config_error); + wps_fail_event(wps->wps, WPS_M7, config_error, + wps->error_indication); break; default: break; diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index 9953efbca..316e1f69f 100644 --- a/src/wps/wps_i.h +++ b/src/wps/wps_i.h @@ -102,6 +102,7 @@ struct wps_data { * config_error - Configuration Error value to be used in NACK */ u16 config_error; + u16 error_indication; int ext_reg; int int_reg; @@ -213,7 +214,7 @@ void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, size_t encr_len); void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg, - u16 config_error); + u16 config_error, u16 error_indication); void wps_success_event(struct wps_context *wps); void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part); void wps_pbc_overlap_event(struct wps_context *wps); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index e2681f70b..ec429f831 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -2597,21 +2597,24 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps, return WPS_FAILURE; ret = wps_process_m3(wps, msg, &attr); if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) - wps_fail_event(wps->wps, WPS_M3, wps->config_error); + wps_fail_event(wps->wps, WPS_M3, wps->config_error, + wps->error_indication); break; case WPS_M5: if (wps_validate_m5(msg) < 0) return WPS_FAILURE; ret = wps_process_m5(wps, msg, &attr); if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) - wps_fail_event(wps->wps, WPS_M5, wps->config_error); + wps_fail_event(wps->wps, WPS_M5, wps->config_error, + wps->error_indication); break; case WPS_M7: if (wps_validate_m7(msg) < 0) return WPS_FAILURE; ret = wps_process_m7(wps, msg, &attr); if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) - wps_fail_event(wps->wps, WPS_M7, wps->config_error); + wps_fail_event(wps->wps, WPS_M7, wps->config_error, + wps->error_indication); break; default: wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d", @@ -2756,16 +2759,20 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps, switch (old_state) { case RECV_M3: - wps_fail_event(wps->wps, WPS_M2, config_error); + wps_fail_event(wps->wps, WPS_M2, config_error, + wps->error_indication); break; case RECV_M5: - wps_fail_event(wps->wps, WPS_M4, config_error); + wps_fail_event(wps->wps, WPS_M4, config_error, + wps->error_indication); break; case RECV_M7: - wps_fail_event(wps->wps, WPS_M6, config_error); + wps_fail_event(wps->wps, WPS_M6, config_error, + wps->error_indication); break; case RECV_DONE: - wps_fail_event(wps->wps, WPS_M8, config_error); + wps_fail_event(wps->wps, WPS_M8, config_error, + wps->error_indication); break; default: break; @@ -2949,7 +2956,8 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps, if (ret == WPS_FAILURE) { wps->state = SEND_WSC_NACK; wps_fail_event(wps->wps, WPS_WSC_DONE, - wps->config_error); + wps->config_error, + wps->error_indication); } return ret; default: diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 6dfea2f44..04761b41d 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -410,15 +410,36 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s, } +static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = { + "No Error", /* WPS_EI_NO_ERROR */ + "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */ + "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */ +}; + static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { - wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d", - fail->msg, fail->config_error); - if (wpa_s->parent && wpa_s->parent != wpa_s) - wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL - "msg=%d config_error=%d", + if (fail->error_indication > 0 && + fail->error_indication < NUM_WPS_EI_VALUES) { + wpa_msg(wpa_s, MSG_INFO, + WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", + fail->msg, fail->config_error, fail->error_indication, + wps_event_fail_reason[fail->error_indication]); + if (wpa_s->parent && wpa_s->parent != wpa_s) + wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL + "msg=%d config_error=%d reason=%d (%s)", + fail->msg, fail->config_error, + fail->error_indication, + wps_event_fail_reason[fail->error_indication]); + } else { + wpa_msg(wpa_s, MSG_INFO, + WPS_EVENT_FAIL "msg=%d config_error=%d", fail->msg, fail->config_error); + if (wpa_s->parent && wpa_s->parent != wpa_s) + wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL + "msg=%d config_error=%d", + fail->msg, fail->config_error); + } wpas_clear_wps(wpa_s); wpas_notify_wps_event_fail(wpa_s, fail); }