diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 6eb759023..eb2f20e3b 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -4549,6 +4549,153 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) } +static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd) +{ + struct p2ps_provision *p2ps_prov; + char *pos; + size_t info_len = 0; + char *info = NULL; + u8 role = P2PS_SETUP_NONE; + long long unsigned val; + + pos = os_strstr(cmd, "info="); + if (pos) { + pos += 5; + info_len = os_strlen(pos); + + if (info_len) { + info = os_malloc(info_len + 1); + if (info) { + info_len = utf8_unescape(pos, info_len, + info, info_len + 1); + } else + info_len = 0; + } + } + + p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1); + if (p2ps_prov == NULL) { + os_free(info); + return NULL; + } + + if (info) { + os_memcpy(p2ps_prov->info, info, info_len); + p2ps_prov->info[info_len] = '\0'; + os_free(info); + } + + pos = os_strstr(cmd, "status="); + if (pos) + p2ps_prov->status = atoi(pos + 7); + else + p2ps_prov->status = -1; + + pos = os_strstr(cmd, "adv_id="); + if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL) + goto invalid_args; + p2ps_prov->adv_id = val; + + pos = os_strstr(cmd, "method="); + if (pos) + p2ps_prov->method = strtol(pos + 7, NULL, 16); + else + p2ps_prov->method = 0; + + pos = os_strstr(cmd, "session="); + if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL) + goto invalid_args; + p2ps_prov->session_id = val; + + pos = os_strstr(cmd, "adv_mac="); + if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac)) + goto invalid_args; + + pos = os_strstr(cmd, "session_mac="); + if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac)) + goto invalid_args; + + /* force conncap with tstCap (no sanity checks) */ + pos = os_strstr(cmd, "tstCap="); + if (pos) { + role = strtol(pos + 7, NULL, 16); + } else { + pos = os_strstr(cmd, "role="); + if (pos) { + role = strtol(pos + 5, NULL, 16); + if (role != P2PS_SETUP_CLIENT && + role != P2PS_SETUP_GROUP_OWNER) + role = P2PS_SETUP_NONE; + } + } + p2ps_prov->role = role; + + return p2ps_prov; + +invalid_args: + os_free(p2ps_prov); + return NULL; +} + + +static int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 addr[ETH_ALEN]; + struct p2ps_provision *p2ps_prov; + char *pos; + + /* id= [role=] [info=] */ + + wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd); + + if (hwaddr_aton(cmd, addr)) + return -1; + + pos = cmd + 17; + if (*pos != ' ') + return -1; + + p2ps_prov = p2p_parse_asp_provision_cmd(pos); + if (!p2ps_prov) + return -1; + + if (p2ps_prov->status < 0) { + os_free(p2ps_prov); + return -1; + } + + return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP, + p2ps_prov); +} + + +static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 addr[ETH_ALEN]; + struct p2ps_provision *p2ps_prov; + char *pos; + + /* id= adv_mac= conncap= + * session= mac= [info=] + */ + + wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd); + if (hwaddr_aton(cmd, addr)) + return -1; + + pos = cmd + 17; + if (*pos != ' ') + return -1; + + p2ps_prov = p2p_parse_asp_provision_cmd(pos); + if (!p2ps_prov) + return -1; + + return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP, + p2ps_prov); +} + + static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -7856,6 +8003,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) { wpas_p2p_stop_find(wpa_s); + } else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) { + if (p2p_ctrl_asp_provision(wpa_s, buf + 18)) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) { + if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23)) + reply_len = -1; } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) { reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply, reply_size); diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index fdadffa3b..2f06c35ae 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1825,6 +1825,20 @@ static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc, } +static int wpa_cli_cmd_p2p_asp_provision(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION", 3, argc, argv); +} + + +static int wpa_cli_cmd_p2p_asp_provision_resp(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION_RESP", 2, argc, argv); +} + + static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -2878,6 +2892,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" }, { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none, "= stop P2P Devices search" }, + { "p2p_asp_provision", wpa_cli_cmd_p2p_asp_provision, NULL, + cli_cmd_flag_none, + " adv_id= conncap= [info=] = provision with a P2P ASP Device" }, + { "p2p_asp_provision_resp", wpa_cli_cmd_p2p_asp_provision_resp, NULL, + cli_cmd_flag_none, + " adv_id= [role] [info=] = provision with a P2P ASP Device" }, { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect, cli_cmd_flag_none, " <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },