mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-23 06:02:37 +01:00
p2p: Start a basic P2P Group after GO Negotiation
Use the ap.c API to start an AP on a P2P_GO interface after we've been selected as the GO in the GO Negotiation.
This commit is contained in:
parent
185b676f31
commit
68cb9d38bf
125
src/p2p.c
125
src/p2p.c
@ -55,6 +55,7 @@
|
|||||||
#include "src/frame-xchg.h"
|
#include "src/frame-xchg.h"
|
||||||
#include "src/nl80211util.h"
|
#include "src/nl80211util.h"
|
||||||
#include "src/netconfig.h"
|
#include "src/netconfig.h"
|
||||||
|
#include "src/ap.h"
|
||||||
#include "src/p2p.h"
|
#include "src/p2p.h"
|
||||||
|
|
||||||
struct p2p_device {
|
struct p2p_device {
|
||||||
@ -110,6 +111,7 @@ struct p2p_device {
|
|||||||
uint8_t conn_peer_interface_addr[6];
|
uint8_t conn_peer_interface_addr[6];
|
||||||
|
|
||||||
struct p2p_group_id_attr go_group_id;
|
struct p2p_group_id_attr go_group_id;
|
||||||
|
struct ap_state *group;
|
||||||
|
|
||||||
bool enabled : 1;
|
bool enabled : 1;
|
||||||
bool have_roc_cookie : 1;
|
bool have_roc_cookie : 1;
|
||||||
@ -123,6 +125,7 @@ struct p2p_device {
|
|||||||
bool disconnecting : 1;
|
bool disconnecting : 1;
|
||||||
bool is_go : 1;
|
bool is_go : 1;
|
||||||
bool conn_go_tie_breaker : 1;
|
bool conn_go_tie_breaker : 1;
|
||||||
|
bool conn_peer_added : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct p2p_discovery_user {
|
struct p2p_discovery_user {
|
||||||
@ -217,8 +220,9 @@ static void p2p_discovery_user_free(void *data)
|
|||||||
|
|
||||||
static inline bool p2p_peer_operational(struct p2p_peer *peer)
|
static inline bool p2p_peer_operational(struct p2p_peer *peer)
|
||||||
{
|
{
|
||||||
return peer && peer->dev->conn_netdev && !peer->dev->conn_wsc_bss &&
|
return peer && peer->dev->conn_netdev && !peer->dev->disconnecting &&
|
||||||
!peer->wsc.pending_connect && !peer->dev->disconnecting;
|
((!peer->dev->is_go && !peer->dev->conn_wsc_bss) ||
|
||||||
|
(peer->dev->is_go && peer->dev->conn_peer_added));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool p2p_peer_match(const void *a, const void *b)
|
static bool p2p_peer_match(const void *a, const void *b)
|
||||||
@ -457,6 +461,14 @@ static void p2p_connection_reset(struct p2p_device *dev)
|
|||||||
if (dev->conn_enrollee)
|
if (dev->conn_enrollee)
|
||||||
wsc_enrollee_cancel(dev->conn_enrollee, false);
|
wsc_enrollee_cancel(dev->conn_enrollee, false);
|
||||||
|
|
||||||
|
if (dev->group) {
|
||||||
|
ap_free(dev->group);
|
||||||
|
dev->group = NULL;
|
||||||
|
dev->conn_peer_added = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->capability.group_caps = 0;
|
||||||
|
|
||||||
if (dev->conn_netdev) {
|
if (dev->conn_netdev) {
|
||||||
struct l_genl_msg *msg;
|
struct l_genl_msg *msg;
|
||||||
uint64_t wdev_id = netdev_get_wdev_id(dev->conn_netdev);
|
uint64_t wdev_id = netdev_get_wdev_id(dev->conn_netdev);
|
||||||
@ -628,10 +640,12 @@ static void p2p_peer_connect_done(struct p2p_device *dev)
|
|||||||
{
|
{
|
||||||
struct p2p_peer *peer = dev->conn_peer;
|
struct p2p_peer *peer = dev->conn_peer;
|
||||||
|
|
||||||
|
if (!dev->is_go) {
|
||||||
/* We can free anything potentially needed for a retry */
|
/* We can free anything potentially needed for a retry */
|
||||||
scan_bss_free(dev->conn_wsc_bss);
|
scan_bss_free(dev->conn_wsc_bss);
|
||||||
dev->conn_wsc_bss = NULL;
|
dev->conn_wsc_bss = NULL;
|
||||||
explicit_bzero(dev->conn_psk, 32);
|
explicit_bzero(dev->conn_psk, 32);
|
||||||
|
}
|
||||||
|
|
||||||
dbus_pending_reply(&peer->wsc.pending_connect,
|
dbus_pending_reply(&peer->wsc.pending_connect,
|
||||||
l_dbus_message_new_method_return(
|
l_dbus_message_new_method_return(
|
||||||
@ -649,6 +663,96 @@ static void p2p_peer_connect_done(struct p2p_device *dev)
|
|||||||
"ConnectedIP");
|
"ConnectedIP");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void p2p_group_event(enum ap_event_type type, const void *event_data,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct p2p_device *dev = user_data;
|
||||||
|
|
||||||
|
l_debug("type=%i", type);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case AP_EVENT_START_FAILED:
|
||||||
|
case AP_EVENT_STOPPING:
|
||||||
|
dev->group = NULL;
|
||||||
|
p2p_connect_failed(dev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AP_EVENT_STARTED:
|
||||||
|
ap_push_button(dev->group);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AP_EVENT_STATION_ADDED:
|
||||||
|
dev->conn_peer_added = true;
|
||||||
|
p2p_peer_connect_done(dev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AP_EVENT_STATION_REMOVED:
|
||||||
|
dev->conn_peer_added = false;
|
||||||
|
p2p_connect_failed(dev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AP_EVENT_REGISTRATION_START:
|
||||||
|
/* Don't validate the P2P IE or WFD IE at this stage */
|
||||||
|
break;
|
||||||
|
case AP_EVENT_REGISTRATION_SUCCESS:
|
||||||
|
dev->capability.group_caps &= ~P2P_GROUP_CAP_GROUP_FORMATION;
|
||||||
|
break;
|
||||||
|
case AP_EVENT_PBC_MODE_EXIT:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct ap_ops p2p_go_ops = {
|
||||||
|
.handle_event = p2p_group_event,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void p2p_group_start(struct p2p_device *dev)
|
||||||
|
{
|
||||||
|
struct ap_config *config = l_new(struct ap_config, 1);
|
||||||
|
|
||||||
|
config->ssid = l_strdup(dev->go_group_id.ssid);
|
||||||
|
config->channel = dev->listen_channel;
|
||||||
|
config->wsc_name = l_strdup(dev->device_info.device_name);
|
||||||
|
config->wsc_primary_device_type = dev->device_info.primary_device_type;
|
||||||
|
config->no_cck_rates = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Section 3.2.1: "The Credentials for a P2P Group issued to a
|
||||||
|
* P2P Device shall: [...]
|
||||||
|
* - Use a Network Key Type of 64 Hex characters."
|
||||||
|
*
|
||||||
|
* This implies we have to send the PSK and not the passphrase to
|
||||||
|
* the WSC clients. For simplicity we directly generate random
|
||||||
|
* PSKs and don't currently respect the requirement to maintain
|
||||||
|
* a passphrase. We have no practical use for the passphrase and
|
||||||
|
* it's a little costlier to generate for the same cryptographic
|
||||||
|
* strength as the PSK.
|
||||||
|
*/
|
||||||
|
if (!l_getrandom(config->psk, 32)) {
|
||||||
|
l_error("l_getrandom() failed");
|
||||||
|
ap_config_free(config);
|
||||||
|
p2p_connect_failed(dev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Section 3.1.4.4: "It shall only allow association by the
|
||||||
|
* P2P Device that it is currently in Group Formation with."
|
||||||
|
*/
|
||||||
|
config->authorized_macs = l_memdup(dev->conn_peer_interface_addr, 6);
|
||||||
|
config->authorized_macs_num = 1;
|
||||||
|
|
||||||
|
dev->capability.group_caps |= P2P_GROUP_CAP_GO;
|
||||||
|
dev->capability.group_caps |= P2P_GROUP_CAP_GROUP_FORMATION;
|
||||||
|
|
||||||
|
dev->group = ap_start(dev->conn_netdev, config, &p2p_go_ops, dev);
|
||||||
|
if (!dev->group) {
|
||||||
|
ap_config_free(config);
|
||||||
|
p2p_connect_failed(dev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void p2p_netconfig_event_handler(enum netconfig_event event,
|
static void p2p_netconfig_event_handler(enum netconfig_event event,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
@ -682,7 +786,7 @@ static void p2p_dhcp_timeout_destroy(void *user_data)
|
|||||||
dev->conn_dhcp_timeout = NULL;
|
dev->conn_dhcp_timeout = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void p2p_start_dhcp(struct p2p_device *dev)
|
static void p2p_start_dhcp_client(struct p2p_device *dev)
|
||||||
{
|
{
|
||||||
uint32_t ifindex = netdev_get_ifindex(dev->conn_netdev);
|
uint32_t ifindex = netdev_get_ifindex(dev->conn_netdev);
|
||||||
unsigned int dhcp_timeout_val;
|
unsigned int dhcp_timeout_val;
|
||||||
@ -723,7 +827,7 @@ static void p2p_netdev_connect_cb(struct netdev *netdev,
|
|||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case NETDEV_RESULT_OK:
|
case NETDEV_RESULT_OK:
|
||||||
p2p_start_dhcp(dev);
|
p2p_start_dhcp_client(dev);
|
||||||
break;
|
break;
|
||||||
case NETDEV_RESULT_AUTHENTICATION_FAILED:
|
case NETDEV_RESULT_AUTHENTICATION_FAILED:
|
||||||
case NETDEV_RESULT_ASSOCIATION_FAILED:
|
case NETDEV_RESULT_ASSOCIATION_FAILED:
|
||||||
@ -1034,10 +1138,14 @@ static void p2p_device_netdev_notify(struct netdev *netdev,
|
|||||||
case NETDEV_WATCH_EVENT_NEW:
|
case NETDEV_WATCH_EVENT_NEW:
|
||||||
/* Ignore the event if we're already connecting/connected */
|
/* Ignore the event if we're already connecting/connected */
|
||||||
if (dev->conn_enrollee || dev->conn_retry_count ||
|
if (dev->conn_enrollee || dev->conn_retry_count ||
|
||||||
!netdev_get_is_up(netdev))
|
dev->group || !netdev_get_is_up(netdev))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (dev->is_go)
|
||||||
|
p2p_group_start(dev);
|
||||||
|
else
|
||||||
p2p_provision_connect(dev);
|
p2p_provision_connect(dev);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case NETDEV_WATCH_EVENT_DEL:
|
case NETDEV_WATCH_EVENT_DEL:
|
||||||
dev->conn_netdev = NULL;
|
dev->conn_netdev = NULL;
|
||||||
@ -1094,13 +1202,14 @@ static void p2p_device_new_interface_destroy(void *user_data)
|
|||||||
|
|
||||||
static void p2p_device_interface_create(struct p2p_device *dev)
|
static void p2p_device_interface_create(struct p2p_device *dev)
|
||||||
{
|
{
|
||||||
uint32_t iftype = NL80211_IFTYPE_P2P_CLIENT;
|
uint32_t iftype = dev->is_go ? NL80211_IFTYPE_P2P_GO :
|
||||||
|
NL80211_IFTYPE_P2P_CLIENT;
|
||||||
char ifname[32];
|
char ifname[32];
|
||||||
uint32_t wiphy_id = dev->wdev_id >> 32;
|
uint32_t wiphy_id = dev->wdev_id >> 32;
|
||||||
struct l_genl_msg *msg;
|
struct l_genl_msg *msg;
|
||||||
|
|
||||||
snprintf(ifname, sizeof(ifname), "wlan%i-p2p-cl%i",
|
snprintf(ifname, sizeof(ifname), "wlan%i-p2p-%s%i",
|
||||||
wiphy_id, dev->conn_num++);
|
wiphy_id, dev->is_go ? "go" : "cl", dev->conn_num++);
|
||||||
l_debug("creating %s", ifname);
|
l_debug("creating %s", ifname);
|
||||||
|
|
||||||
msg = l_genl_msg_new(NL80211_CMD_NEW_INTERFACE);
|
msg = l_genl_msg_new(NL80211_CMD_NEW_INTERFACE);
|
||||||
|
Loading…
Reference in New Issue
Block a user