WPS: Add preliminary NFC connection handover support for Enrollee
This commit adds new wpa_supplicant ctrl_iface commands to allow external programs to go through NFC connection handover mechanism with wpa_supplicant taking care of the WPS processing. This version includes only the case where wpa_supplicant is operating as a station/Enrollee. Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
86cf382b80
commit
e65552ddf2
7 changed files with 382 additions and 1 deletions
|
@ -17,6 +17,7 @@
|
|||
#define FLAG_CHUNK (1 << 5)
|
||||
#define FLAG_SHORT_RECORD (1 << 4)
|
||||
#define FLAG_ID_LENGTH_PRESENT (1 << 3)
|
||||
#define FLAG_TNF_NFC_FORUM (0x01)
|
||||
#define FLAG_TNF_RFC2046 (0x02)
|
||||
|
||||
struct ndef_record {
|
||||
|
@ -168,3 +169,78 @@ struct wpabuf * ndef_build_wifi(const struct wpabuf *buf)
|
|||
FLAG_TNF_RFC2046, wifi_handover_type,
|
||||
os_strlen(wifi_handover_type), NULL, 0, buf);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * ndef_build_wifi_hr(void)
|
||||
{
|
||||
struct wpabuf *rn, *cr, *ac_payload, *ac, *hr_payload, *hr;
|
||||
struct wpabuf *carrier, *hc;
|
||||
|
||||
rn = wpabuf_alloc(2);
|
||||
if (rn == NULL)
|
||||
return NULL;
|
||||
wpabuf_put_be16(rn, os_random() & 0xffff);
|
||||
|
||||
cr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "cr", 2,
|
||||
NULL, 0, rn);
|
||||
wpabuf_free(rn);
|
||||
|
||||
if (cr == NULL)
|
||||
return NULL;
|
||||
|
||||
ac_payload = wpabuf_alloc(4);
|
||||
if (ac_payload == NULL) {
|
||||
wpabuf_free(cr);
|
||||
return NULL;
|
||||
}
|
||||
wpabuf_put_u8(ac_payload, 0x01); /* Carrier Flags: CRS=1 "active" */
|
||||
wpabuf_put_u8(ac_payload, 0x01); /* Carrier Data Reference Length */
|
||||
wpabuf_put_u8(ac_payload, '0'); /* Carrier Data Reference: "0" */
|
||||
wpabuf_put_u8(ac_payload, 0); /* Aux Data Reference Count */
|
||||
|
||||
ac = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "ac", 2,
|
||||
NULL, 0, ac_payload);
|
||||
wpabuf_free(ac_payload);
|
||||
if (ac == NULL) {
|
||||
wpabuf_free(cr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr_payload = wpabuf_alloc(1 + wpabuf_len(cr) + wpabuf_len(ac));
|
||||
if (hr_payload == NULL) {
|
||||
wpabuf_free(cr);
|
||||
wpabuf_free(ac);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpabuf_put_u8(hr_payload, 0x12); /* Connection Handover Version 1.2 */
|
||||
wpabuf_put_buf(hr_payload, cr);
|
||||
wpabuf_put_buf(hr_payload, ac);
|
||||
wpabuf_free(cr);
|
||||
wpabuf_free(ac);
|
||||
|
||||
hr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "Hr", 2,
|
||||
NULL, 0, hr_payload);
|
||||
wpabuf_free(hr_payload);
|
||||
if (hr == NULL)
|
||||
return NULL;
|
||||
|
||||
carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
|
||||
if (carrier == NULL) {
|
||||
wpabuf_free(hr);
|
||||
return NULL;
|
||||
}
|
||||
wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
|
||||
wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
|
||||
wpabuf_put_str(carrier, wifi_handover_type);
|
||||
|
||||
hc = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
|
||||
"0", 1, carrier);
|
||||
wpabuf_free(carrier);
|
||||
if (hc == NULL) {
|
||||
wpabuf_free(hr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wpabuf_concat(hr, hc);
|
||||
}
|
||||
|
|
|
@ -858,6 +858,7 @@ struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
|
|||
/* ndef.c */
|
||||
struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
|
||||
struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
|
||||
struct wpabuf * ndef_build_wifi_hr(void);
|
||||
|
||||
#ifdef CONFIG_WPS_STRICT
|
||||
int wps_validate_beacon(const struct wpabuf *wps_ie);
|
||||
|
|
|
@ -351,3 +351,27 @@ an AP) using a special value "nfc-pw" in place of the PIN parameter. If
|
|||
the ER functionality has been started (wps_er_start), the NFC password
|
||||
token is used to enable enrollment of a new station (that was the source
|
||||
of the NFC password token).
|
||||
|
||||
"nfc_get_handover_req <NDEF> <WPS>" command can be used to build the
|
||||
contents of a Handover Request Message for connection handover. The
|
||||
first argument selects the format of the output data and the second
|
||||
argument selects which type of connection handover is requested (WPS =
|
||||
Wi-Fi handover as specified in WSC 2.0).
|
||||
|
||||
"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
|
||||
contents of a Handover Select Message for connection handover when this
|
||||
does not depend on the contents of the Handover Request Message. The
|
||||
first argument selects the format of the output data and the second
|
||||
argument selects which type of connection handover is requested (WPS =
|
||||
Wi-Fi handover as specified in WSC 2.0).
|
||||
|
||||
"nfc_rx_handover_req <hexdump of payload>" is used to indicate receipt
|
||||
of NFC connection handover request. The payload may include multiple
|
||||
carriers the the applicable ones are matched based on the media
|
||||
type. The reply data is contents for the Handover Select Message
|
||||
(hexdump).
|
||||
|
||||
"nfc_rx_handover_sel <hexdump of payload>" is used to indicate receipt
|
||||
of NFC connection handover select. The payload may include multiple
|
||||
carriers the the applicable ones are matched based on the media
|
||||
type.
|
||||
|
|
|
@ -846,6 +846,149 @@ static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
|
||||
char *reply, size_t max_len)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
int res;
|
||||
|
||||
buf = wpas_wps_nfc_handover_req(wpa_s);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
|
||||
wpabuf_len(buf));
|
||||
reply[res++] = '\n';
|
||||
reply[res] = '\0';
|
||||
|
||||
wpabuf_free(buf);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
|
||||
char *cmd, char *reply,
|
||||
size_t max_len)
|
||||
{
|
||||
char *pos;
|
||||
|
||||
pos = os_strchr(cmd, ' ');
|
||||
if (pos == NULL)
|
||||
return -1;
|
||||
*pos++ = '\0';
|
||||
|
||||
if (os_strcmp(cmd, "NDEF") != 0)
|
||||
return -1;
|
||||
|
||||
if (os_strcmp(pos, "WPS") == 0) {
|
||||
return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
|
||||
max_len);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
|
||||
char *reply, size_t max_len)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
int res;
|
||||
|
||||
buf = wpas_wps_nfc_handover_sel(wpa_s);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
|
||||
wpabuf_len(buf));
|
||||
reply[res++] = '\n';
|
||||
reply[res] = '\0';
|
||||
|
||||
wpabuf_free(buf);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
|
||||
char *cmd, char *reply,
|
||||
size_t max_len)
|
||||
{
|
||||
char *pos;
|
||||
|
||||
pos = os_strchr(cmd, ' ');
|
||||
if (pos == NULL)
|
||||
return -1;
|
||||
*pos++ = '\0';
|
||||
|
||||
if (os_strcmp(cmd, "NDEF") != 0)
|
||||
return -1;
|
||||
|
||||
if (os_strcmp(pos, "WPS") == 0) {
|
||||
return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
|
||||
max_len);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
|
||||
char *cmd, char *reply,
|
||||
size_t max_len)
|
||||
{
|
||||
size_t len;
|
||||
struct wpabuf *buf;
|
||||
int ret;
|
||||
|
||||
len = os_strlen(cmd);
|
||||
if (len & 0x01)
|
||||
return -1;
|
||||
len /= 2;
|
||||
|
||||
buf = wpabuf_alloc(len);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
|
||||
wpabuf_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
|
||||
wpabuf_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
|
||||
char *cmd)
|
||||
{
|
||||
size_t len;
|
||||
struct wpabuf *buf;
|
||||
int ret;
|
||||
|
||||
len = os_strlen(cmd);
|
||||
if (len & 0x01)
|
||||
return -1;
|
||||
len /= 2;
|
||||
|
||||
buf = wpabuf_alloc(len);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
|
||||
wpabuf_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
|
||||
wpabuf_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
|
||||
|
||||
|
@ -4502,7 +4645,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
|||
int reply_len;
|
||||
|
||||
if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
|
||||
os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
|
||||
os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
|
||||
os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
|
||||
os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
|
||||
(const u8 *) buf, os_strlen(buf));
|
||||
} else {
|
||||
|
@ -4640,6 +4785,18 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
|||
if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
|
||||
buf + 17))
|
||||
reply_len = -1;
|
||||
} else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
|
||||
reply_len = wpas_ctrl_nfc_get_handover_req(
|
||||
wpa_s, buf + 21, reply, reply_size);
|
||||
} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
|
||||
reply_len = wpas_ctrl_nfc_get_handover_sel(
|
||||
wpa_s, buf + 21, reply, reply_size);
|
||||
} else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
|
||||
reply_len = wpas_ctrl_nfc_rx_handover_req(
|
||||
wpa_s, buf + 20, reply, reply_size);
|
||||
} else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
|
||||
if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
|
||||
reply_len = -1;
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
|
||||
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
|
||||
|
|
|
@ -796,6 +796,72 @@ static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
int ret;
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
|
||||
if (argc != 1) {
|
||||
printf("Invalid 'nfc_rx_handover_req' command - one argument "
|
||||
"is required.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buflen = 21 + os_strlen(argv[0]);
|
||||
buf = os_malloc(buflen);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
|
||||
|
||||
ret = wpa_ctrl_command(ctrl, buf);
|
||||
os_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
int ret;
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
|
||||
if (argc != 1) {
|
||||
printf("Invalid 'nfc_rx_handover_sel' command - one argument "
|
||||
"is required.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buflen = 21 + os_strlen(argv[0]);
|
||||
buf = os_malloc(buflen);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]);
|
||||
|
||||
ret = wpa_ctrl_command(ctrl, buf);
|
||||
os_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
|
||||
|
||||
|
@ -2436,6 +2502,18 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
|
|||
{ "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
|
||||
cli_cmd_flag_sensitive,
|
||||
"<hexdump of payload> = report read NFC tag with WPS data" },
|
||||
{ "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
|
||||
cli_cmd_flag_none,
|
||||
"<NDEF> <WPS> = create NFC handover request" },
|
||||
{ "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
|
||||
cli_cmd_flag_none,
|
||||
"<NDEF> <WPS> = create NFC handover select" },
|
||||
{ "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
|
||||
cli_cmd_flag_none,
|
||||
"<hexdump of payload> = report received NFC handover request" },
|
||||
{ "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
|
||||
cli_cmd_flag_none,
|
||||
"<hexdump of payload> = report received NFC handover select" },
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
{ "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
|
||||
cli_cmd_flag_sensitive,
|
||||
|
|
|
@ -1975,6 +1975,45 @@ int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
return ndef_build_wifi_hr();
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
|
||||
const struct wpabuf *data)
|
||||
{
|
||||
/* TODO */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
|
||||
const struct wpabuf *data)
|
||||
{
|
||||
struct wpabuf *wps;
|
||||
int ret;
|
||||
|
||||
wps = ndef_parse_wifi(data);
|
||||
if (wps == NULL)
|
||||
return -1;
|
||||
wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
|
||||
"payload from NFC connection handover");
|
||||
wpa_hexdump_buf_key(MSG_DEBUG, "WPS: NFC payload", wps);
|
||||
ret = wpas_wps_nfc_tag_process(wpa_s, wps);
|
||||
wpabuf_free(wps);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
|
||||
|
||||
|
|
|
@ -69,6 +69,12 @@ 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);
|
||||
struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s);
|
||||
struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s);
|
||||
int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
|
||||
const struct wpabuf *data);
|
||||
int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
|
||||
const struct wpabuf *data);
|
||||
void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_scan_results *scan_res);
|
||||
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
|
||||
|
|
Loading…
Reference in a new issue