P2P: Update D-Bus network object semantics during group formation

Do not emit network objects during P2P group formation since such
network objects can confuse certain apps. Instead, a persistent group
object is created to allow apps to keep track of persistent groups.
Persistent group objects only represent the info needed to recreate the
group.

Also fixes a minor bug in the handling of persistent group objects
during WPS operations.

Signed-off-by: Jayant Sane <jayant.sane@intel.com>
This commit is contained in:
Jayant Sane 2011-06-23 21:25:13 +03:00 committed by Jouni Malinen
parent c988980d95
commit c2762e410f
10 changed files with 442 additions and 11 deletions

View file

@ -1281,6 +1281,102 @@ error:
dbus_message_unref(msg);
}
/**
* wpas_dbus_signal_persistent_group - Send a persistent group related
* event signal
* @wpa_s: %wpa_supplicant network interface data
* @id: new persistent group id
* @sig_name: signal name - PersistentGroupAdded, PersistentGroupRemoved
* @properties: determines if add second argument with object properties
*
* Notify listeners about an event related to persistent groups.
*/
static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
int id, const char *sig_name,
int properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
DBusMessageIter iter, iter_dict;
char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
return;
os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
wpa_s->dbus_new_path, id);
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
sig_name);
if (msg == NULL)
return;
dbus_message_iter_init_append(msg, &iter);
path = pgrp_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
&path))
goto err;
if (properties) {
if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
goto err;
wpa_dbus_get_object_properties(
iface, pgrp_obj_path,
WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP,
&iter_dict);
if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
goto err;
}
dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
return;
err:
wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
dbus_message_unref(msg);
}
/**
* wpas_dbus_signal_persistent_group_added - Send a persistent_group
* added signal
* @wpa_s: %wpa_supplicant network interface data
* @id: new persistent group id
*
* Notify listeners about addition of a new persistent group.
*/
static void wpas_dbus_signal_persistent_group_added(
struct wpa_supplicant *wpa_s, int id)
{
wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupAdded",
TRUE);
}
/**
* wpas_dbus_signal_persistent_group_removed - Send a persistent_group
* removed signal
* @wpa_s: %wpa_supplicant network interface data
* @id: persistent group id
*
* Notify listeners about removal of a persistent group.
*/
static void wpas_dbus_signal_persistent_group_removed(
struct wpa_supplicant *wpa_s, int id)
{
wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupRemoved",
TRUE);
}
#endif /*CONFIG_P2P*/
@ -1654,6 +1750,14 @@ int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
struct network_handler_args *arg;
char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
/*
* If it is a persistent group register it as such.
* This is to handle cases where an interface is being initialized
* with a list of networks read from config.
*/
if (network_is_persistent_group(ssid))
return wpas_dbus_register_persistent_group(wpa_s, ssid);
/* Do nothing if the control interface is not turned on */
if (wpa_s == NULL || wpa_s->global == NULL)
return 0;
@ -1716,6 +1820,13 @@ int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
struct wpas_dbus_priv *ctrl_iface;
char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
int ret;
struct wpa_ssid *ssid;
ssid = wpa_config_get_network(wpa_s->conf, nid);
/* If it is a persistent group unregister it as such */
if (ssid && network_is_persistent_group(ssid))
return wpas_dbus_unregister_persistent_group(wpa_s, nid);
/* Do nothing if the control interface is not turned on */
if (wpa_s == NULL || wpa_s->global == NULL ||
@ -2245,6 +2356,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
(WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peergo,
NULL, R
},
{ "PersistentGroups", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
(WPADBusPropertyAccessor) wpas_dbus_getter_persistent_groups,
NULL, R
},
#endif /* CONFIG_P2P */
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
@ -2441,6 +2556,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
END_ARGS
}
},
{ "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
{
{ "path", "o", ARG_OUT },
{ "properties", "a{sv}", ARG_OUT },
END_ARGS
}
},
#endif /* CONFIG_P2P */
{ NULL, NULL, { END_ARGS } }
};
@ -2954,4 +3076,142 @@ void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
wpa_dbus_unregister_object_per_iface(ctrl_iface, groupmember_obj_path);
}
static const struct wpa_dbus_property_desc
wpas_dbus_persistent_group_properties[] = {
{ "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
(WPADBusPropertyAccessor)
wpas_dbus_getter_persistent_group_properties,
NULL,
R
},
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
/* No signals intended for persistent group objects */
/**
* wpas_dbus_register_persistent_group - Register a configured(saved)
* persistent group with dbus
* @wpa_s: wpa_supplicant interface structure
* @ssid: persistent group (still represented as a network within wpa)
* configuration data
* Returns: 0 on success, -1 on failure
*
* Registers a persistent group representing object with dbus.
*/
int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
struct wpas_dbus_priv *ctrl_iface;
struct wpa_dbus_object_desc *obj_desc;
struct network_handler_args *arg;
char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
/* Do nothing if the control interface is not turned on */
if (wpa_s == NULL || wpa_s->global == NULL)
return 0;
/* Make sure ssid is a persistent group */
if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
return -1; /* should we return w/o complaining? */
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
return 0;
/*
* Intentionally not coming up with different numbering scheme
* for persistent groups.
*/
os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
wpa_s->dbus_new_path, ssid->id);
wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'",
pgrp_obj_path);
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
"object description");
goto err;
}
/*
* Reusing the same context structure as that for networks
* since these are represented using same data structure.
*/
/* allocate memory for handlers arguments */
arg = os_zalloc(sizeof(struct network_handler_args));
if (!arg) {
wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
"arguments for method");
goto err;
}
arg->wpa_s = wpa_s;
arg->ssid = ssid;
wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
wpas_dbus_persistent_group_properties,
NULL);
if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path,
wpa_s->ifname, obj_desc))
goto err;
wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id);
return 0;
err:
free_dbus_object_desc(obj_desc);
return -1;
}
/**
* wpas_dbus_unregister_persistent_group - Unregister a persistent_group
* from dbus
* @wpa_s: wpa_supplicant interface structure
* @nid: network id
* Returns: 0 on success, -1 on failure
*
* Unregisters persistent group representing object from dbus
*
* NOTE: There is a slight issue with the semantics here. While the
* implementation simply means the persistent group is unloaded from memory,
* it should not get interpreted as the group is actually being erased/removed
* from persistent storage as well.
*/
int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
int nid)
{
struct wpas_dbus_priv *ctrl_iface;
char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
int ret;
/* Do nothing if the control interface is not turned on */
if (wpa_s == NULL || wpa_s->global == NULL ||
wpa_s->dbus_new_path == NULL)
return 0;
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
return 0;
os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
wpa_s->dbus_new_path, nid);
wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'",
pgrp_obj_path);
ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path);
if (!ret)
wpas_dbus_signal_persistent_group_removed(wpa_s, nid);
return ret;
}
#endif /* CONFIG_P2P */

View file

@ -72,6 +72,14 @@ enum wpas_dbus_bss_prop {
#define WPAS_DBUS_NEW_P2P_GROUPS_PART "Groups"
#define WPAS_DBUS_NEW_IFACE_P2P_GROUP WPAS_DBUS_NEW_INTERFACE ".Group"
/*
* Different dbus object for persistent groups so they do not get confused
* with regular (configured) network objects.
*/
#define WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "PersistentGroups"
#define WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP \
WPAS_DBUS_NEW_INTERFACE ".PersistentGroup"
#define WPAS_DBUS_NEW_P2P_PEERS_PART "Peers"
#define WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer"
@ -170,6 +178,10 @@ void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status);
void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
const struct wpa_ssid *ssid);
int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
int nid);
void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
int status, const u8 *bssid);
void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
@ -344,6 +356,18 @@ wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
{
}
static inline int wpas_dbus_register_persistent_group(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
return 0;
}
static inline int wpas_dbus_unregister_persistent_group(
struct wpa_supplicant *wpa_s, int nid)
{
return 0;
}
static inline void
wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status)
{

View file

@ -2508,6 +2508,7 @@ DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
}
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
if (!network_is_persistent_group(ssid))
num++;
paths = os_zalloc(num * sizeof(char *));
@ -2518,6 +2519,8 @@ DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
/* Loop through configured networks and append object path of each */
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (network_is_persistent_group(ssid))
continue;
paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
if (paths[i] == NULL) {
reply = dbus_message_new_error(message,

View file

@ -1207,6 +1207,90 @@ DBusMessage *wpas_dbus_getter_p2p_peer_ies(DBusMessage * message,
}
/**
* wpas_dbus_getter_persistent_groups - Get array of peristent group objects
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
* Returns: a dbus message containing an array of all persistent group
* dbus object paths.
*
* Getter for "Networks" property.
*/
DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
DBusMessage *reply = NULL;
struct wpa_ssid *ssid;
char **paths;
unsigned int i = 0, num = 0;
if (wpa_s->conf == NULL) {
wpa_printf(MSG_ERROR, "dbus: "
"wpas_dbus_getter_persistent_groups: "
"An error occurred getting persistent groups list");
return wpas_dbus_error_unknown_error(message, NULL);
}
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
if (network_is_persistent_group(ssid))
num++;
paths = os_zalloc(num * sizeof(char *));
if (!paths) {
return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
NULL);
}
/* Loop through configured networks and append object path of each */
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (!network_is_persistent_group(ssid))
continue;
paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
if (paths[i] == NULL) {
reply = dbus_message_new_error(message,
DBUS_ERROR_NO_MEMORY,
NULL);
goto out;
}
/* Construct the object path for this network. */
os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
wpa_s->dbus_new_path, ssid->id);
}
reply = wpas_dbus_simple_array_property_getter(message,
DBUS_TYPE_OBJECT_PATH,
paths, num);
out:
while (i)
os_free(paths[--i]);
os_free(paths);
return reply;
}
/**
* wpas_dbus_getter_persistent_group_properties - Get options for a persistent
* group
* @message: Pointer to incoming dbus message
* @net: wpa_supplicant structure for a network interface and
* wpa_ssid structure for a configured persistent group (internally network)
* Returns: DBus message with network properties or DBus error on failure
*
* Getter for "Properties" property of a persistent group.
*/
DBusMessage * wpas_dbus_getter_persistent_group_properties(
DBusMessage *message, struct network_handler_args *net)
{
/*
* Leveraging the fact that persistent group object is still
* represented in same manner as network within.
*/
return wpas_dbus_getter_network_properties(message, net);
}
/*
* Group object properties accessor methods
*/

View file

@ -139,4 +139,13 @@ DBusMessage *wpas_dbus_setter_p2p_group_properties(
DBusMessage *message,
struct wpa_supplicant *wpa_s);
/*
* P2P Persistent Group properties
*/
DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_getter_persistent_group_properties(
DBusMessage *message, struct network_handler_args *net);
#endif /* DBUS_NEW_HANDLERS_P2P_H */

View file

@ -206,13 +206,28 @@ void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s)
void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
/*
* Networks objects created during any P2P activities should not be
* exposed out. They might/will confuse certain non-P2P aware
* applications since these network objects won't behave like
* regular ones.
*/
if (wpa_s->global->p2p_group_formation != wpa_s)
wpas_dbus_register_network(wpa_s, ssid);
}
void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
wpas_dbus_register_persistent_group(wpa_s, ssid);
}
void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
if (wpa_s->global->p2p_group_formation != wpa_s)
wpas_dbus_unregister_network(wpa_s, ssid->id);
}

View file

@ -111,5 +111,7 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int network_id,
int client);
void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
#endif /* NOTIFY_H */

View file

@ -295,7 +295,15 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
int id = ssid->id;
if (ssid == wpa_s->current_ssid)
wpa_s->current_ssid = NULL;
wpas_notify_network_removed(wpa_s, ssid);
/*
* Networks objects created during any P2P activities are not
* exposed out as they might/will confuse certain non-P2P aware
* applications since these network objects won't behave like
* regular ones.
*
* Likewise, we don't send out network removed signals for such
* network objects.
*/
wpa_config_remove_network(wpa_s->conf, id);
wpa_supplicant_clear_status(wpa_s);
} else {
@ -400,7 +408,16 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
s = wpa_config_add_network(wpa_s->conf);
if (s == NULL)
return -1;
wpas_notify_network_added(wpa_s, s);
/*
* Instead of network_added we emit persistent_group_added
* notification. Also to keep the defense checks in
* persistent_group obj registration method, we set the
* relevant flags in s to designate it as a persistent group.
*/
s->p2p_group = 1;
s->p2p_persistent_group = 1;
wpas_notify_persistent_group_added(wpa_s, s);
wpa_config_set_network_defaults(s);
}
@ -904,7 +921,6 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
if (ssid == NULL)
return;
wpas_notify_network_added(wpa_s, ssid);
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->p2p_group = 1;
@ -3303,7 +3319,6 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return -1;
wpas_notify_network_added(wpa_s, ssid);
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->proto = WPA_PROTO_RSN;
@ -3312,7 +3327,6 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->ssid = os_malloc(params->ssid_len);
if (ssid->ssid == NULL) {
wpas_notify_network_removed(wpa_s, ssid);
wpa_config_remove_network(wpa_s->conf, ssid->id);
return -1;
}

View file

@ -17,6 +17,7 @@
#include "utils/list.h"
#include "common/defs.h"
#include "config_ssid.h"
extern const char *wpa_supplicant_version;
extern const char *wpa_supplicant_license;
@ -642,4 +643,14 @@ void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
/* eap_register.c */
int eap_register_methods(void);
/**
* Utility method to tell if a given network is a persistent group
* @ssid: Network object
* Returns: 1 if network is a persistent group, 0 otherwise
*/
static inline int network_is_persistent_group(struct wpa_ssid *ssid)
{
return ((ssid->disabled == 2) || ssid->p2p_persistent_group);
}
#endif /* WPA_SUPPLICANT_I_H */

View file

@ -780,9 +780,18 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
ssid = wpa_s->conf->ssid;
while (ssid) {
int was_disabled = ssid->disabled;
/*
* In case the network object corresponds to a persistent group
* then do not send out network disabled signal. In addition,
* do not change disabled status of persistent network objects
* from 2 to 1 should we connect to another network.
*/
if (was_disabled != 2) {
ssid->disabled = ssid != selected;
if (was_disabled != ssid->disabled)
wpas_notify_network_enabled_changed(wpa_s, ssid);
wpas_notify_network_enabled_changed(wpa_s,
ssid);
}
ssid = ssid->next;
}
wpa_s->disconnected = 0;