diff --git a/hostapd/README-WPS b/hostapd/README-WPS index c052df658..44e3d9d25 100644 --- a/hostapd/README-WPS +++ b/hostapd/README-WPS @@ -239,6 +239,14 @@ hostapd_cli wps_ap_pin set [timeout] hostapd_cli get_config - display the current configuration +hostapd_cli wps_config +examples: + hostapd_cli wps_config testing WPA2PSK CCMP 12345678 + hostapd_cli wps_config "no security" OPEN NONE "" + + must be one of the following: OPEN WPAPSK WPA2PSK + must be one of the following: NONE WEP TKIP CCMP + Credential generation and configuration changes ----------------------------------------------- diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 2cdcdc13a..d0ed897c8 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -490,6 +490,33 @@ static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt, return -1; } + + +static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt) +{ + char *pos; + char *ssid, *auth, *encr = NULL, *key = NULL; + + ssid = txt; + pos = os_strchr(txt, ' '); + if (!pos) + return -1; + *pos++ = '\0'; + + auth = pos; + pos = os_strchr(pos, ' '); + if (pos) { + *pos++ = '\0'; + encr = pos; + pos = os_strchr(pos, ' '); + if (pos) { + *pos++ = '\0'; + key = pos; + } + } + + return hostapd_wps_config_ap(hapd, ssid, auth, encr, key); +} #endif /* CONFIG_WPS */ @@ -821,6 +848,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) { reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11, reply, reply_size); + } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) { + if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0) + reply_len = -1; #endif /* CONFIG_WPS */ } else if (os_strcmp(buf, "GET_CONFIG") == 0) { reply_len = hostapd_ctrl_iface_get_config(hapd, reply, diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index c0d647f5a..3fdaa1596 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -96,6 +96,7 @@ static const char *commands_help = " wps_oob use WPS with out-of-band (UFD)\n" #endif /* CONFIG_WPS_OOB */ " wps_ap_pin [params..] enable/disable AP PIN\n" +" wps_config configure AP\n" #endif /* CONFIG_WPS */ " get_config show current configuration\n" " help show this usage help\n" @@ -458,6 +459,50 @@ static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]); return wpa_ctrl_command(ctrl, buf); } + + +static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char buf[256]; + char ssid_hex[2 * 32 + 1]; + char key_hex[2 * 64 + 1]; + int i; + + if (argc < 1) { + printf("Invalid 'wps_config' command - at least two arguments " + "are required.\n"); + return -1; + } + + ssid_hex[0] = '\0'; + for (i = 0; i < 32; i++) { + if (argv[0][i] == '\0') + break; + os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]); + } + + key_hex[0] = '\0'; + if (argc > 3) { + for (i = 0; i < 64; i++) { + if (argv[3][i] == '\0') + break; + os_snprintf(&key_hex[i * 2], 3, "%02x", + argv[3][i]); + } + } + + if (argc > 3) + snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s", + ssid_hex, argv[1], argv[2], key_hex); + else if (argc > 2) + snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s", + ssid_hex, argv[1], argv[2]); + else + snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s", + ssid_hex, argv[1]); + return wpa_ctrl_command(ctrl, buf); +} #endif /* CONFIG_WPS */ @@ -649,6 +694,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = { { "wps_oob", hostapd_cli_cmd_wps_oob }, #endif /* CONFIG_WPS_OOB */ { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin }, + { "wps_config", hostapd_cli_cmd_wps_config }, #endif /* CONFIG_WPS */ { "get_config", hostapd_cli_cmd_get_config }, { "help", hostapd_cli_cmd_help }, diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index f4cbd5e61..75a058657 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -1286,3 +1286,52 @@ void hostapd_wps_update_ie(struct hostapd_data *hapd) { hostapd_wps_for_each(hapd, wps_update_ie, NULL); } + + +int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid, + const char *auth, const char *encr, const char *key) +{ + struct wps_credential cred; + size_t len; + + os_memset(&cred, 0, sizeof(cred)); + + len = os_strlen(ssid); + if ((len & 1) || len > 2 * sizeof(cred.ssid) || + hexstr2bin(ssid, cred.ssid, len / 2)) + return -1; + cred.ssid_len = len / 2; + + if (os_strncmp(auth, "OPEN", 4) == 0) + cred.auth_type = WPS_AUTH_OPEN; + else if (os_strncmp(auth, "WPAPSK", 6) == 0) + cred.auth_type = WPS_AUTH_WPAPSK; + else if (os_strncmp(auth, "WPA2PSK", 7) == 0) + cred.auth_type = WPS_AUTH_WPA2PSK; + else + return -1; + + if (encr) { + if (os_strncmp(encr, "NONE", 4) == 0) + cred.encr_type = WPS_ENCR_NONE; + else if (os_strncmp(encr, "WEP", 3) == 0) + cred.encr_type = WPS_ENCR_WEP; + else if (os_strncmp(encr, "TKIP", 4) == 0) + cred.encr_type = WPS_ENCR_TKIP; + else if (os_strncmp(encr, "CCMP", 4) == 0) + cred.encr_type = WPS_ENCR_AES; + else + return -1; + } else + cred.encr_type = WPS_ENCR_NONE; + + if (key) { + len = os_strlen(key); + if ((len & 1) || len > 2 * sizeof(cred.key) || + hexstr2bin(key, cred.key, len / 2)) + return -1; + cred.key_len = len / 2; + } + + return wps_registrar_config_ap(hapd->wps->registrar, &cred); +} diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h index fac736bf4..36401be38 100644 --- a/src/ap/wps_hostapd.h +++ b/src/ap/wps_hostapd.h @@ -34,6 +34,8 @@ const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd); int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, int timeout); void hostapd_wps_update_ie(struct hostapd_data *hapd); +int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid, + const char *auth, const char *encr, const char *key); #else /* CONFIG_WPS */ diff --git a/src/wps/wps.h b/src/wps/wps.h index beb21b64a..bf8bddc44 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -736,6 +736,8 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, int wps_registrar_update_ie(struct wps_registrar *reg); int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr, char *buf, size_t buflen); +int wps_registrar_config_ap(struct wps_registrar *reg, + struct wps_credential *cred); unsigned int wps_pin_checksum(unsigned int pin); unsigned int wps_pin_valid(unsigned int pin); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 7da374a45..b2c76de98 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -3161,3 +3161,43 @@ int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr, return len; } + + +int wps_registrar_config_ap(struct wps_registrar *reg, + struct wps_credential *cred) +{ +#ifdef CONFIG_WPS2 + printf("encr_type=0x%x\n", cred->encr_type); + if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | + WPS_ENCR_AES))) { + if (cred->encr_type & WPS_ENCR_WEP) { + wpa_printf(MSG_INFO, "WPS: Reject new AP settings " + "due to WEP configuration"); + return -1; + } + + wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to " + "invalid encr_type 0x%x", cred->encr_type); + return -1; + } + + if ((cred->encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == + WPS_ENCR_TKIP) { + wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> " + "TKIP+AES"); + cred->encr_type |= WPS_ENCR_AES; + } + + if ((cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == + WPS_AUTH_WPAPSK) { + wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> " + "WPAPSK+WPA2PSK"); + cred->auth_type |= WPS_AUTH_WPA2PSK; + } +#endif /* CONFIG_WPS2 */ + + if (reg->wps->cred_cb) + return reg->wps->cred_cb(reg->wps->cb_ctx, cred); + + return -1; +}