P2PS: Process P2PS provisioning commands
This extends wpas_p2p_prov_disc() implementation to accept P2PS parameters. None of the callers are yet using this functionality; the following commit introduces a user. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
369678ad14
commit
6d9085145c
8 changed files with 268 additions and 9 deletions
|
@ -159,6 +159,13 @@ struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p)
|
|||
}
|
||||
|
||||
|
||||
void p2p_set_intended_addr(struct p2p_data *p2p, const u8 *intended_addr)
|
||||
{
|
||||
if (p2p && intended_addr)
|
||||
os_memcpy(p2p->intended_addr, intended_addr, ETH_ALEN);
|
||||
}
|
||||
|
||||
|
||||
u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
|
||||
{
|
||||
struct p2p_device *dev = NULL;
|
||||
|
|
|
@ -1955,6 +1955,13 @@ const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p);
|
|||
*/
|
||||
unsigned int p2p_get_group_num_members(struct p2p_group *group);
|
||||
|
||||
/**
|
||||
* p2p_client_limit_reached - Check if client limit is reached
|
||||
* @group: P2P group context from p2p_group_init()
|
||||
* Returns: 1 if no of clients limit reached
|
||||
*/
|
||||
int p2p_client_limit_reached(struct p2p_group *group);
|
||||
|
||||
/**
|
||||
* p2p_iterate_group_members - Iterate group members
|
||||
* @group: P2P group context from p2p_group_init()
|
||||
|
@ -2170,6 +2177,8 @@ void p2p_loop_on_known_peers(struct p2p_data *p2p,
|
|||
|
||||
void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem);
|
||||
|
||||
void p2p_set_intended_addr(struct p2p_data *p2p, const u8 *intended_addr);
|
||||
|
||||
struct p2ps_advertisement *
|
||||
p2p_service_p2ps_id(struct p2p_data *p2p, u32 adv_id);
|
||||
int p2p_service_add_asp(struct p2p_data *p2p, int auto_accept, u32 adv_id,
|
||||
|
|
|
@ -988,6 +988,15 @@ unsigned int p2p_get_group_num_members(struct p2p_group *group)
|
|||
}
|
||||
|
||||
|
||||
int p2p_client_limit_reached(struct p2p_group *group)
|
||||
{
|
||||
if (!group || !group->cfg)
|
||||
return 1;
|
||||
|
||||
return group->num_members >= group->cfg->max_clients;
|
||||
}
|
||||
|
||||
|
||||
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
|
||||
{
|
||||
struct p2p_group_member *iter = *next;
|
||||
|
|
|
@ -4699,7 +4699,7 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
|
|||
else if (os_strstr(pos, " auto") != NULL)
|
||||
use = WPAS_P2P_PD_AUTO;
|
||||
|
||||
return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
|
||||
return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -730,7 +730,7 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
|
|||
wpa_s = wpa_s->p2p_dev;
|
||||
|
||||
if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
|
||||
WPAS_P2P_PD_FOR_GO_NEG) < 0)
|
||||
WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
|
||||
return wpas_dbus_error_unknown_error(message,
|
||||
"Failed to send provision discovery request");
|
||||
|
||||
|
|
|
@ -123,6 +123,8 @@ static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
|
|||
static void wpas_stop_listen(void *ctx);
|
||||
static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
|
||||
static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
|
||||
static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
|
||||
enum wpa_driver_if_type type);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -475,6 +477,34 @@ static int wpas_p2p_disconnect_safely(struct wpa_supplicant *wpa_s,
|
|||
}
|
||||
|
||||
|
||||
/* Find an interface for a P2P group where we are the GO */
|
||||
static struct wpa_supplicant *
|
||||
wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
struct wpa_supplicant *save = NULL;
|
||||
struct wpa_ssid *s;
|
||||
|
||||
if (!wpa_s)
|
||||
return NULL;
|
||||
|
||||
for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
|
||||
for (s = wpa_s->conf->ssid; s; s = s->next) {
|
||||
if (s->disabled || !s->p2p_group ||
|
||||
s->mode != WPAS_MODE_P2P_GO)
|
||||
continue;
|
||||
|
||||
/* Prefer a group with connected clients */
|
||||
if (p2p_get_group_num_members(wpa_s->p2p_group))
|
||||
return wpa_s;
|
||||
save = wpa_s;
|
||||
}
|
||||
}
|
||||
|
||||
/* No group with connected clients, so pick the one without (if any) */
|
||||
return save;
|
||||
}
|
||||
|
||||
|
||||
/* Find an active P2P group where we are the GO */
|
||||
static struct wpa_ssid * wpas_p2p_group_go_ssid(struct wpa_supplicant *wpa_s,
|
||||
u8 *bssid)
|
||||
|
@ -516,6 +546,193 @@ wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s)
|
|||
}
|
||||
|
||||
|
||||
static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = ctx, *tmp_wpa_s;
|
||||
struct wpa_ssid *s;
|
||||
u8 conncap = P2PS_SETUP_NONE;
|
||||
unsigned int owned_members = 0;
|
||||
unsigned int owner = 0;
|
||||
unsigned int client = 0;
|
||||
struct wpa_supplicant *go_wpa_s;
|
||||
struct wpa_ssid *persistent_go;
|
||||
int p2p_no_group_iface;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role);
|
||||
|
||||
/*
|
||||
* For non-concurrent capable devices:
|
||||
* If persistent_go, then no new.
|
||||
* If GO, then no client.
|
||||
* If client, then no GO.
|
||||
*/
|
||||
go_wpa_s = wpas_p2p_get_go_group(wpa_s);
|
||||
persistent_go = wpas_p2p_get_persistent_go(wpa_s);
|
||||
p2p_no_group_iface = wpa_s->conf->p2p_no_group_iface;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "P2P: GO(iface)=%p persistent(ssid)=%p",
|
||||
go_wpa_s, persistent_go);
|
||||
|
||||
for (tmp_wpa_s = wpa_s->global->ifaces; tmp_wpa_s;
|
||||
tmp_wpa_s = tmp_wpa_s->next) {
|
||||
for (s = tmp_wpa_s->conf->ssid; s; s = s->next) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d",
|
||||
tmp_wpa_s, s, s->disabled,
|
||||
s->p2p_group, s->mode);
|
||||
if (!s->disabled && s->p2p_group) {
|
||||
if (s->mode == WPAS_MODE_P2P_GO) {
|
||||
owned_members +=
|
||||
p2p_get_group_num_members(
|
||||
tmp_wpa_s->p2p_group);
|
||||
owner++;
|
||||
} else
|
||||
client++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If not concurrent, restrict our choices */
|
||||
if (p2p_no_group_iface) {
|
||||
wpa_printf(MSG_DEBUG, "P2P: p2p_no_group_iface");
|
||||
|
||||
if (client)
|
||||
return P2PS_SETUP_NONE;
|
||||
|
||||
if (go_wpa_s) {
|
||||
if (role == P2PS_SETUP_CLIENT ||
|
||||
incoming == P2PS_SETUP_GROUP_OWNER ||
|
||||
p2p_client_limit_reached(go_wpa_s->p2p_group))
|
||||
return P2PS_SETUP_NONE;
|
||||
|
||||
return P2PS_SETUP_GROUP_OWNER;
|
||||
}
|
||||
|
||||
if (persistent_go) {
|
||||
if (role == P2PS_SETUP_NONE || role == P2PS_SETUP_NEW) {
|
||||
if (!incoming)
|
||||
return P2PS_SETUP_GROUP_OWNER |
|
||||
P2PS_SETUP_CLIENT;
|
||||
if (incoming == P2PS_SETUP_NEW) {
|
||||
u8 r;
|
||||
|
||||
if (os_get_random(&r, sizeof(r)) < 0 ||
|
||||
(r & 1))
|
||||
return P2PS_SETUP_CLIENT;
|
||||
return P2PS_SETUP_GROUP_OWNER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If a required role has been specified, handle it here */
|
||||
if (role && role != P2PS_SETUP_NEW) {
|
||||
switch (incoming) {
|
||||
case P2PS_SETUP_NONE:
|
||||
case P2PS_SETUP_NEW:
|
||||
case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
|
||||
case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
|
||||
conncap = role;
|
||||
goto grp_owner;
|
||||
|
||||
case P2PS_SETUP_GROUP_OWNER:
|
||||
/*
|
||||
* Must be a complimentary role - cannot be a client to
|
||||
* more than one peer.
|
||||
*/
|
||||
if (incoming == role || client)
|
||||
return P2PS_SETUP_NONE;
|
||||
|
||||
return P2PS_SETUP_CLIENT;
|
||||
|
||||
case P2PS_SETUP_CLIENT:
|
||||
/* Must be a complimentary role */
|
||||
if (incoming != role) {
|
||||
conncap = P2PS_SETUP_GROUP_OWNER;
|
||||
goto grp_owner;
|
||||
}
|
||||
|
||||
default:
|
||||
return P2PS_SETUP_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, we only will support ownership of one group, and being a
|
||||
* client of one group. Therefore, if we have either an existing GO
|
||||
* group, or an existing client group, we will not do a new GO
|
||||
* negotiation, but rather try to re-use the existing groups.
|
||||
*/
|
||||
switch (incoming) {
|
||||
case P2PS_SETUP_NONE:
|
||||
case P2PS_SETUP_NEW:
|
||||
if (client)
|
||||
conncap = P2PS_SETUP_GROUP_OWNER;
|
||||
else if (!owned_members)
|
||||
conncap = P2PS_SETUP_NEW;
|
||||
else if (incoming == P2PS_SETUP_NONE)
|
||||
conncap = P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT;
|
||||
else
|
||||
conncap = P2PS_SETUP_CLIENT;
|
||||
break;
|
||||
|
||||
case P2PS_SETUP_CLIENT:
|
||||
conncap = P2PS_SETUP_GROUP_OWNER;
|
||||
break;
|
||||
|
||||
case P2PS_SETUP_GROUP_OWNER:
|
||||
if (!client)
|
||||
conncap = P2PS_SETUP_CLIENT;
|
||||
break;
|
||||
|
||||
case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
|
||||
case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
|
||||
if (client)
|
||||
conncap = P2PS_SETUP_GROUP_OWNER;
|
||||
else {
|
||||
u8 r;
|
||||
|
||||
if (os_get_random(&r, sizeof(r)) < 0 ||
|
||||
(r & 1))
|
||||
conncap = P2PS_SETUP_CLIENT;
|
||||
else
|
||||
conncap = P2PS_SETUP_GROUP_OWNER;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return P2PS_SETUP_NONE;
|
||||
}
|
||||
|
||||
grp_owner:
|
||||
if ((conncap & P2PS_SETUP_GROUP_OWNER) ||
|
||||
(!incoming && (conncap & P2PS_SETUP_NEW))) {
|
||||
if (go_wpa_s && p2p_client_limit_reached(go_wpa_s->p2p_group))
|
||||
conncap &= ~P2PS_SETUP_GROUP_OWNER;
|
||||
wpa_printf(MSG_DEBUG, "P2P: GOs:%d members:%d conncap:%d",
|
||||
owner, owned_members, conncap);
|
||||
|
||||
s = wpas_p2p_get_persistent_go(wpa_s);
|
||||
|
||||
if (!s && !owner && p2p_no_group_iface) {
|
||||
p2p_set_intended_addr(wpa_s->global->p2p,
|
||||
wpa_s->own_addr);
|
||||
} else if (!s && !owner) {
|
||||
if (wpas_p2p_add_group_interface(wpa_s,
|
||||
WPA_IF_P2P_GO) < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"P2P: Failed to allocate a new interface for the group");
|
||||
return P2PS_SETUP_NONE;
|
||||
}
|
||||
p2p_set_intended_addr(wpa_s->global->p2p,
|
||||
wpa_s->pending_interface_addr);
|
||||
}
|
||||
}
|
||||
|
||||
return conncap;
|
||||
}
|
||||
|
||||
|
||||
static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
|
||||
enum p2p_group_removal_reason removal_reason)
|
||||
{
|
||||
|
@ -6293,13 +6510,24 @@ int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s)
|
|||
|
||||
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
|
||||
const char *config_method,
|
||||
enum wpas_p2p_prov_disc_use use)
|
||||
enum wpas_p2p_prov_disc_use use,
|
||||
struct p2ps_provision *p2ps_prov)
|
||||
{
|
||||
u16 config_methods;
|
||||
|
||||
wpa_s->p2p_fallback_to_go_neg = 0;
|
||||
wpa_s->pending_pd_use = NORMAL_PD;
|
||||
if (os_strncmp(config_method, "display", 7) == 0)
|
||||
if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) {
|
||||
p2ps_prov->conncap = p2ps_group_capability(
|
||||
wpa_s, P2PS_SETUP_NONE, p2ps_prov->role);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"P2P: %s conncap: %d - ASP parsed: %x %x %d %s",
|
||||
__func__, p2ps_prov->conncap,
|
||||
p2ps_prov->adv_id, p2ps_prov->conncap,
|
||||
p2ps_prov->status, p2ps_prov->info);
|
||||
|
||||
config_methods = 0;
|
||||
} else if (os_strncmp(config_method, "display", 7) == 0)
|
||||
config_methods = WPS_CONFIG_DISPLAY;
|
||||
else if (os_strncmp(config_method, "keypad", 6) == 0)
|
||||
config_methods = WPS_CONFIG_KEYPAD;
|
||||
|
@ -6308,6 +6536,7 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
|
|||
config_methods = WPS_CONFIG_PUSHBUTTON;
|
||||
else {
|
||||
wpa_printf(MSG_DEBUG, "P2P: Unknown config method");
|
||||
os_free(p2ps_prov);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -6328,10 +6557,12 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
|
||||
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) {
|
||||
os_free(p2ps_prov);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr, NULL,
|
||||
return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr, p2ps_prov,
|
||||
config_methods, use == WPAS_P2P_PD_FOR_JOIN,
|
||||
0, 1);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ enum p2p_send_action_result;
|
|||
struct p2p_peer_info;
|
||||
struct p2p_channels;
|
||||
struct wps_event_fail;
|
||||
struct p2ps_provision;
|
||||
|
||||
int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
|
||||
const char *conf_p2p_dev);
|
||||
|
@ -41,11 +42,13 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
|
|||
enum wpas_p2p_prov_disc_use {
|
||||
WPAS_P2P_PD_FOR_GO_NEG,
|
||||
WPAS_P2P_PD_FOR_JOIN,
|
||||
WPAS_P2P_PD_AUTO
|
||||
WPAS_P2P_PD_AUTO,
|
||||
WPAS_P2P_PD_FOR_ASP
|
||||
};
|
||||
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
|
||||
const char *config_method,
|
||||
enum wpas_p2p_prov_disc_use use);
|
||||
enum wpas_p2p_prov_disc_use use,
|
||||
struct p2ps_provision *p2ps_prov);
|
||||
void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
|
||||
const u8 *data, size_t data_len,
|
||||
enum p2p_send_action_result result);
|
||||
|
|
|
@ -771,7 +771,7 @@ struct wpa_supplicant {
|
|||
int force_long_sd;
|
||||
u16 pending_pd_config_methods;
|
||||
enum {
|
||||
NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN
|
||||
NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN, AUTO_PD_ASP
|
||||
} pending_pd_use;
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue