diff --git a/src/wps/wps.h b/src/wps/wps.h index ca2f55c96..dd84f1b7b 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -27,6 +27,7 @@ enum wsc_op_code { struct wps_registrar; struct upnp_wps_device_sm; struct wps_er; +struct wps_parse_attr; /** * struct wps_credential - WPS Credential @@ -818,6 +819,7 @@ int wps_get_oob_method(char *method); int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev, int registrar); struct wpabuf * wps_get_oob_cred(struct wps_context *wps); +int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr); int wps_attr_text(struct wpabuf *data, char *buf, char *end); struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname, diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c index 35ebec00a..16412ca33 100644 --- a/src/wps/wps_common.c +++ b/src/wps/wps_common.c @@ -437,23 +437,17 @@ static int wps_parse_oob_dev_pwd(struct wps_context *wps, } -static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data) +int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr) { struct wpabuf msg; - struct wps_parse_attr attr; size_t i; - if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) { - wpa_printf(MSG_ERROR, "WPS: OOB credential not found"); - return -1; - } - - for (i = 0; i < attr.num_cred; i++) { + for (i = 0; i < attr->num_cred; i++) { struct wps_credential local_cred; struct wps_parse_attr cattr; os_memset(&local_cred, 0, sizeof(local_cred)); - wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]); + wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]); if (wps_parse_msg(&msg, &cattr) < 0 || wps_process_cred(&cattr, &local_cred)) { wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB " @@ -467,6 +461,19 @@ static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data) } +static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data) +{ + struct wps_parse_attr attr; + + if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) { + wpa_printf(MSG_ERROR, "WPS: OOB credential not found"); + return -1; + } + + return wps_oob_use_cred(wps, &attr); +} + + int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev, int registrar) { diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 2ef42aca2..4a8478c53 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -662,6 +662,33 @@ static int wpa_supplicant_ctrl_iface_wps_nfc_token( return res; } + + +static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read( + struct wpa_supplicant *wpa_s, char *pos) +{ + size_t len; + struct wpabuf *buf; + int ret; + + len = os_strlen(pos); + if (len & 0x01) + return -1; + len /= 2; + + buf = wpabuf_alloc(len); + if (buf == NULL) + return -1; + if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { + wpabuf_free(buf); + return -1; + } + + ret = wpas_wps_nfc_tag_read(wpa_s, buf); + wpabuf_free(buf); + + return ret; +} #endif /* CONFIG_WPS_OOB */ @@ -4100,6 +4127,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) { reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token( wpa_s, buf + 14, reply, reply_size); + } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) { + if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s, + buf + 17)) + reply_len = -1; #endif /* CONFIG_WPS_OOB */ } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) { if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8)) diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index ba311dff3..4d2d31322 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -887,6 +887,32 @@ static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc, } return wpa_ctrl_command(ctrl, cmd); } + + +static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + int ret; + char *buf; + size_t buflen; + + if (argc != 1) { + printf("Invalid 'wps_nfc_tag_read' command - one argument " + "is required.\n"); + return -1; + } + + buflen = 18 + os_strlen(argv[0]); + buf = os_malloc(buflen); + if (buf == NULL) + return -1; + os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]); + + ret = wpa_ctrl_command(ctrl, buf); + os_free(buf); + + return ret; +} #endif /* CONFIG_WPS_OOB */ @@ -3089,6 +3115,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, cli_cmd_flag_none, " = create password token" }, + { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, + cli_cmd_flag_sensitive, + " = report read NFC tag with WPS data" }, #endif /* CONFIG_WPS_OOB */ { "wps_reg", wpa_cli_cmd_wps_reg, cli_cmd_flag_sensitive, diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index bade09f0b..08dd99826 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -1,6 +1,6 @@ /* * wpa_supplicant / WPS integration - * Copyright (c) 2008-2010, Jouni Malinen + * Copyright (c) 2008-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -21,6 +21,7 @@ #include "eap_peer/eap.h" #include "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" +#include "wps/wps_attr_parse.h" #include "config.h" #include "wpa_supplicant_i.h" #include "driver_i.h" @@ -1846,4 +1847,71 @@ int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid) wpa_s->conf->wps_nfc_dev_pw_id); } + +static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s, + struct wps_parse_attr *attr) +{ + if (wps_oob_use_cred(wpa_s->wps, attr) < 0) + return -1; + + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) + return 0; + + wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network " + "based on the received credential added"); + wpa_s->normal_scans = 0; + wpa_supplicant_reinit_autoscan(wpa_s); + wpa_s->disconnected = 0; + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + + return 0; +} + + +static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s, + const struct wpabuf *wps) +{ + struct wps_parse_attr attr; + + wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps); + + if (wps_parse_msg(wps, &attr)) { + wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag"); + return -1; + } + + if (attr.num_cred) + return wpas_wps_use_cred(wpa_s, &attr); + + wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag"); + return -1; +} + + +int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s, + const struct wpabuf *data) +{ + const struct wpabuf *wps = data; + struct wpabuf *tmp = NULL; + int ret; + + if (wpabuf_len(data) < 4) + return -1; + + if (*wpabuf_head_u8(data) != 0x10) { + /* Assume this contains full NDEF record */ + tmp = ndef_parse_wifi(data); + if (tmp == NULL) { + wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF"); + return -1; + } + wps = tmp; + } + + ret = wpas_wps_nfc_tag_process(wpa_s, wps); + wpabuf_free(tmp); + return ret; +} + #endif /* CONFIG_WPS_NFC */ diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index 6ce0e7bc6..38b365576 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -1,6 +1,6 @@ /* * wpa_supplicant / WPS integration - * Copyright (c) 2008-2009, Jouni Malinen + * Copyright (c) 2008-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -64,6 +64,8 @@ int wpas_wps_in_progress(struct wpa_supplicant *wpa_s); void wpas_wps_update_config(struct wpa_supplicant *wpa_s); struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef); int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid); +int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s, + const struct wpabuf *data); #else /* CONFIG_WPS */