diff --git a/src/wps/wps.h b/src/wps/wps.h index eaecbed0e..41082aad2 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -737,6 +737,8 @@ void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id, int wps_er_pbc(struct wps_er *er, const u8 *uuid); int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin, size_t pin_len); +int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin, + size_t pin_len, const struct wps_credential *cred); int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]); char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf, diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index 2bd85bf09..9c47aafcf 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -1501,10 +1501,26 @@ static void wps_er_ap_put_message(struct wps_er_ap *ap, static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg) { enum wps_process_res res; + struct wps_parse_attr attr; + enum wsc_op_code op_code; - res = wps_process_msg(ap->wps, WSC_MSG, msg); + op_code = WSC_MSG; + if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) { + switch (*attr.msg_type) { + case WPS_WSC_ACK: + op_code = WSC_ACK; + break; + case WPS_WSC_NACK: + op_code = WSC_NACK; + break; + case WPS_WSC_DONE: + op_code = WSC_Done; + break; + } + } + + res = wps_process_msg(ap->wps, op_code, msg); if (res == WPS_CONTINUE) { - enum wsc_op_code op_code; struct wpabuf *next = wps_get_msg(ap->wps, &op_code); if (next) { wps_er_ap_put_message(ap, next); @@ -1675,3 +1691,64 @@ int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin, return 0; } + + +static void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1) +{ + struct wps_config cfg; + + if (ap->wps) { + wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in " + "progress with this AP"); + return; + } + + os_memset(&cfg, 0, sizeof(cfg)); + cfg.wps = ap->er->wps; + cfg.registrar = 1; + cfg.new_ap_settings = ap->ap_settings; + ap->wps = wps_init(&cfg); + if (ap->wps == NULL) + return; + ap->wps->ap_settings_cb = NULL; + ap->wps->ap_settings_cb_ctx = NULL; + + wps_er_ap_process(ap, m1); +} + + +int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin, + size_t pin_len, const struct wps_credential *cred) +{ + struct wps_er_ap *ap; + + if (er == NULL) + return -1; + + ap = wps_er_ap_get(er, NULL, uuid); + if (ap == NULL) { + wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config " + "request"); + return -1; + } + if (ap->wps) { + wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing " + "with the AP - cannot start config"); + return -1; + } + + os_free(ap->ap_settings); + ap->ap_settings = os_malloc(sizeof(*cred)); + if (ap->ap_settings == NULL) + return -1; + os_memcpy(ap->ap_settings, cred, sizeof(*cred)); + ap->ap_settings->cred_attr = NULL; + + if (wps_er_send_get_device_info(ap, wps_er_ap_config_m1) < 0) + return -1; + + /* TODO: add PIN without SetSelectedRegistrar trigger to all APs */ + wps_registrar_add_pin(er->wps->registrar, uuid, pin, pin_len, 0); + + return 0; +} diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS index 30ed2aa80..9b6f9c554 100644 --- a/wpa_supplicant/README-WPS +++ b/wpa_supplicant/README-WPS @@ -236,6 +236,15 @@ wps_er_stop wps_er_learn - learn AP configuration +wps_er_config +- examples: + wps_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 testing WPA2PSK CCMP 12345678 + wpa_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 clear OPEN NONE "" + + must be one of the following: OPEN WPAPSK WPA2PSK + must be one of the following: NONE WEP TKIP CCMP + + wps_er_pbc - accept an Enrollee PBC using External Registrar diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 7df65c1f4..5c3a73579 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -330,6 +330,50 @@ static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s, *pin++ = '\0'; return wpas_wps_er_learn(wpa_s, uuid, pin); } + + +static int wpa_supplicant_ctrl_iface_wps_er_config( + struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pin; + char *new_ssid; + char *new_auth; + char *new_encr; + char *new_key; + struct wps_new_ap_settings ap; + + pin = os_strchr(cmd, ' '); + if (pin == NULL) + return -1; + *pin++ = '\0'; + + new_ssid = os_strchr(pin, ' '); + if (new_ssid == NULL) + return -1; + *new_ssid++ = '\0'; + + new_auth = os_strchr(new_ssid, ' '); + if (new_auth == NULL) + return -1; + *new_auth++ = '\0'; + + new_encr = os_strchr(new_auth, ' '); + if (new_encr == NULL) + return -1; + *new_encr++ = '\0'; + + new_key = os_strchr(new_encr, ' '); + if (new_key == NULL) + return -1; + *new_key++ = '\0'; + + os_memset(&ap, 0, sizeof(ap)); + ap.ssid_hex = new_ssid; + ap.auth = new_auth; + ap.encr = new_encr; + ap.key_hex = new_key; + return wpas_wps_er_config(wpa_s, cmd, pin, &ap); +} #endif /* CONFIG_WPS_ER */ #endif /* CONFIG_WPS */ @@ -1810,6 +1854,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) { if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13)) reply_len = -1; + } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) { + if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14)) + reply_len = -1; #endif /* CONFIG_WPS_ER */ #endif /* CONFIG_WPS */ #ifdef CONFIG_IBSS_RSN diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index bd258ab55..6e67231f4 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -602,7 +602,7 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[]) if (argc == 2) res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", argv[0], argv[1]); - else if (argc == 6) { + else if (argc == 5 || argc == 6) { char ssid_hex[2 * 32 + 1]; char key_hex[2 * 64 + 1]; int i; @@ -615,10 +615,13 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[]) } key_hex[0] = '\0'; - for (i = 0; i < 64; i++) { - if (argv[5][i] == '\0') - break; - os_snprintf(&key_hex[i * 2], 3, "%02x", argv[5][i]); + if (argc == 6) { + for (i = 0; i < 64; i++) { + if (argv[5][i] == '\0') + break; + os_snprintf(&key_hex[i * 2], 3, "%02x", + argv[5][i]); + } } res = os_snprintf(cmd, sizeof(cmd), @@ -736,6 +739,57 @@ static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc, } +static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc == 5 || argc == 6) { + char ssid_hex[2 * 32 + 1]; + char key_hex[2 * 64 + 1]; + int i; + + ssid_hex[0] = '\0'; + for (i = 0; i < 32; i++) { + if (argv[2][i] == '\0') + break; + os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]); + } + + key_hex[0] = '\0'; + if (argc == 6) { + for (i = 0; i < 64; i++) { + if (argv[5][i] == '\0') + break; + os_snprintf(&key_hex[i * 2], 3, "%02x", + argv[5][i]); + } + } + + res = os_snprintf(cmd, sizeof(cmd), + "WPS_ER_CONFIG %s %s %s %s %s %s", + argv[0], argv[1], ssid_hex, argv[3], argv[4], + key_hex); + } else { + printf("Invalid WPS_ER_CONFIG command: need six arguments:\n" + "- AP UUID\n" + "- AP PIN\n" + "- new SSID\n" + "- new auth (OPEN, WPAPSK, WPA2PSK)\n" + "- new encr (NONE, WEP, TKIP, CCMP)\n" + "- new key\n"); + return -1; + } + + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long WPS_ER_CONFIG command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; @@ -1647,6 +1701,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "wps_er_learn", wpa_cli_cmd_wps_er_learn, cli_cmd_flag_sensitive, " = learn AP configuration" }, + { "wps_er_config", wpa_cli_cmd_wps_er_config, + cli_cmd_flag_sensitive, + " = configure AP" }, { "ibss_rsn", wpa_cli_cmd_ibss_rsn, cli_cmd_flag_none, " = request RSN authentication with in IBSS" }, diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index a1b8d1fd8..2b90e5746 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -1194,6 +1194,57 @@ int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid, } +int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid, + const char *pin, struct wps_new_ap_settings *settings) +{ + u8 u[UUID_LEN]; + struct wps_credential cred; + size_t len; + + if (uuid_str2bin(uuid, u)) + return -1; + if (settings->ssid_hex == NULL || settings->auth == NULL || + settings->encr == NULL || settings->key_hex == NULL) + return -1; + + os_memset(&cred, 0, sizeof(cred)); + len = os_strlen(settings->ssid_hex); + if ((len & 1) || len > 2 * sizeof(cred.ssid) || + hexstr2bin(settings->ssid_hex, cred.ssid, len / 2)) + return -1; + cred.ssid_len = len / 2; + + len = os_strlen(settings->key_hex); + if ((len & 1) || len > 2 * sizeof(cred.key) || + hexstr2bin(settings->key_hex, cred.key, len / 2)) + return -1; + cred.key_len = len / 2; + + if (os_strcmp(settings->auth, "OPEN") == 0) + cred.auth_type = WPS_AUTH_OPEN; + else if (os_strcmp(settings->auth, "WPAPSK") == 0) + cred.auth_type = WPS_AUTH_WPAPSK; + else if (os_strcmp(settings->auth, "WPA2PSK") == 0) + cred.auth_type = WPS_AUTH_WPA2PSK; + else + return -1; + + if (os_strcmp(settings->encr, "NONE") == 0) + cred.encr_type = WPS_ENCR_NONE; + else if (os_strcmp(settings->encr, "WEP") == 0) + cred.encr_type = WPS_ENCR_WEP; + else if (os_strcmp(settings->encr, "TKIP") == 0) + cred.encr_type = WPS_ENCR_TKIP; + else if (os_strcmp(settings->encr, "CCMP") == 0) + cred.encr_type = WPS_ENCR_AES; + else + return -1; + + return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin, + os_strlen(pin), &cred); +} + + static void wpas_wps_terminate_cb(void *ctx) { wpa_printf(MSG_DEBUG, "WPS ER: Terminated"); diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index ab45c0f9d..701bcb577 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -59,6 +59,8 @@ int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid, int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid); int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid, const char *pin); +int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid, + const char *pin, struct wps_new_ap_settings *settings); int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s); #else /* CONFIG_WPS */