DBus: Add ability to report probe requests
Some applications require knowing about probe requests to identify devices. This can be the case in AP mode to see the devices before they connect, or even in P2P mode when operating as a P2P device to identify non-P2P peers (P2P peers are identified via PeerFound signals). As there are typically a lot of probe requests, require that an interested application subscribes to this signal so the bus isn't always flooded with these notifications. The notifications in DBus are then unicast only to that application. A small test script is also included. Signed-hostap: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
baf513d695
commit
2d43d37ff2
13 changed files with 459 additions and 35 deletions
|
@ -1830,9 +1830,9 @@ static int supp_rates_11b_only(struct ieee802_11_elems *elems)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
|
static enum p2p_probe_req_status
|
||||||
const u8 *dst, const u8 *bssid, const u8 *ie,
|
p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
||||||
size_t ie_len)
|
const u8 *bssid, const u8 *ie, size_t ie_len)
|
||||||
{
|
{
|
||||||
struct ieee802_11_elems elems;
|
struct ieee802_11_elems elems;
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
|
@ -1842,55 +1842,55 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
|
||||||
|
|
||||||
if (!p2p->in_listen || !p2p->drv_in_listen) {
|
if (!p2p->in_listen || !p2p->drv_in_listen) {
|
||||||
/* not in Listen state - ignore Probe Request */
|
/* not in Listen state - ignore Probe Request */
|
||||||
return;
|
return P2P_PREQ_NOT_LISTEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
|
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
|
||||||
ParseFailed) {
|
ParseFailed) {
|
||||||
/* Ignore invalid Probe Request frames */
|
/* Ignore invalid Probe Request frames */
|
||||||
return;
|
return P2P_PREQ_MALFORMED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elems.p2p == NULL) {
|
if (elems.p2p == NULL) {
|
||||||
/* not a P2P probe - ignore it */
|
/* not a P2P probe - ignore it */
|
||||||
return;
|
return P2P_PREQ_NOT_P2P;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dst && !is_broadcast_ether_addr(dst) &&
|
if (dst && !is_broadcast_ether_addr(dst) &&
|
||||||
os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
|
os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
|
||||||
/* Not sent to the broadcast address or our P2P Device Address
|
/* Not sent to the broadcast address or our P2P Device Address
|
||||||
*/
|
*/
|
||||||
return;
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bssid && !is_broadcast_ether_addr(bssid)) {
|
if (bssid && !is_broadcast_ether_addr(bssid)) {
|
||||||
/* Not sent to the Wildcard BSSID */
|
/* Not sent to the Wildcard BSSID */
|
||||||
return;
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN ||
|
if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN ||
|
||||||
os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
|
os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
|
||||||
0) {
|
0) {
|
||||||
/* not using P2P Wildcard SSID - ignore */
|
/* not using P2P Wildcard SSID - ignore */
|
||||||
return;
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (supp_rates_11b_only(&elems)) {
|
if (supp_rates_11b_only(&elems)) {
|
||||||
/* Indicates support for 11b rates only */
|
/* Indicates support for 11b rates only */
|
||||||
return;
|
return P2P_PREQ_NOT_P2P;
|
||||||
}
|
}
|
||||||
|
|
||||||
os_memset(&msg, 0, sizeof(msg));
|
os_memset(&msg, 0, sizeof(msg));
|
||||||
if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
|
if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
|
||||||
/* Could not parse P2P attributes */
|
/* Could not parse P2P attributes */
|
||||||
return;
|
return P2P_PREQ_NOT_P2P;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.device_id &&
|
if (msg.device_id &&
|
||||||
os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) {
|
os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) {
|
||||||
/* Device ID did not match */
|
/* Device ID did not match */
|
||||||
p2p_parse_free(&msg);
|
p2p_parse_free(&msg);
|
||||||
return;
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check Requested Device Type match */
|
/* Check Requested Device Type match */
|
||||||
|
@ -1898,12 +1898,14 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
|
||||||
!p2p_match_dev_type(p2p, msg.wps_attributes)) {
|
!p2p_match_dev_type(p2p, msg.wps_attributes)) {
|
||||||
/* No match with Requested Device Type */
|
/* No match with Requested Device Type */
|
||||||
p2p_parse_free(&msg);
|
p2p_parse_free(&msg);
|
||||||
return;
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
}
|
}
|
||||||
p2p_parse_free(&msg);
|
p2p_parse_free(&msg);
|
||||||
|
|
||||||
if (!p2p->cfg->send_probe_resp)
|
if (!p2p->cfg->send_probe_resp) {
|
||||||
return; /* Response generated elsewhere */
|
/* Response generated elsewhere */
|
||||||
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
|
}
|
||||||
|
|
||||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
"P2P: Reply to P2P Probe Request in Listen state");
|
"P2P: Reply to P2P Probe Request in Listen state");
|
||||||
|
@ -1916,12 +1918,12 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
|
||||||
*/
|
*/
|
||||||
ies = p2p_build_probe_resp_ies(p2p);
|
ies = p2p_build_probe_resp_ies(p2p);
|
||||||
if (ies == NULL)
|
if (ies == NULL)
|
||||||
return;
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
|
|
||||||
buf = wpabuf_alloc(200 + wpabuf_len(ies));
|
buf = wpabuf_alloc(200 + wpabuf_len(ies));
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
wpabuf_free(ies);
|
wpabuf_free(ies);
|
||||||
return;
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = NULL;
|
resp = NULL;
|
||||||
|
@ -1964,15 +1966,20 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
|
||||||
p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf);
|
p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf);
|
||||||
|
|
||||||
wpabuf_free(buf);
|
wpabuf_free(buf);
|
||||||
|
|
||||||
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
enum p2p_probe_req_status
|
||||||
const u8 *bssid, const u8 *ie, size_t ie_len)
|
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
||||||
|
const u8 *bssid, const u8 *ie, size_t ie_len)
|
||||||
{
|
{
|
||||||
|
enum p2p_probe_req_status res;
|
||||||
|
|
||||||
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
|
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
|
||||||
|
|
||||||
p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
|
res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
|
||||||
|
|
||||||
if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
|
if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
|
||||||
p2p->go_neg_peer &&
|
p2p->go_neg_peer &&
|
||||||
|
@ -1983,7 +1990,7 @@ int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
||||||
"P2P: Found GO Negotiation peer - try to start GO "
|
"P2P: Found GO Negotiation peer - try to start GO "
|
||||||
"negotiation from timeout");
|
"negotiation from timeout");
|
||||||
eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
|
eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
|
||||||
return 1;
|
return P2P_PREQ_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
|
if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
|
||||||
|
@ -1995,10 +2002,10 @@ int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
||||||
"P2P: Found Invite peer - try to start Invite from "
|
"P2P: Found Invite peer - try to start Invite from "
|
||||||
"timeout");
|
"timeout");
|
||||||
eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
|
eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
|
||||||
return 1;
|
return P2P_PREQ_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1086,6 +1086,23 @@ void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr);
|
||||||
|
|
||||||
/* Event notifications from lower layer driver operations */
|
/* Event notifications from lower layer driver operations */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum p2p_probe_req_status
|
||||||
|
*
|
||||||
|
* @P2P_PREQ_MALFORMED: frame was not well-formed
|
||||||
|
* @P2P_PREQ_NOT_LISTEN: device isn't in listen state, frame ignored
|
||||||
|
* @P2P_PREQ_NOT_P2P: frame was not a P2P probe request
|
||||||
|
* @P2P_PREQ_P2P_NOT_PROCESSED: frame was P2P but wasn't processed
|
||||||
|
* @P2P_PREQ_P2P_PROCESSED: frame has been processed by P2P
|
||||||
|
*/
|
||||||
|
enum p2p_probe_req_status {
|
||||||
|
P2P_PREQ_MALFORMED,
|
||||||
|
P2P_PREQ_NOT_LISTEN,
|
||||||
|
P2P_PREQ_NOT_P2P,
|
||||||
|
P2P_PREQ_NOT_PROCESSED,
|
||||||
|
P2P_PREQ_PROCESSED
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* p2p_probe_req_rx - Report reception of a Probe Request frame
|
* p2p_probe_req_rx - Report reception of a Probe Request frame
|
||||||
* @p2p: P2P module context from p2p_init()
|
* @p2p: P2P module context from p2p_init()
|
||||||
|
@ -1094,10 +1111,11 @@ void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr);
|
||||||
* @bssid: BSSID if available or %NULL
|
* @bssid: BSSID if available or %NULL
|
||||||
* @ie: Information elements from the Probe Request frame body
|
* @ie: Information elements from the Probe Request frame body
|
||||||
* @ie_len: Length of ie buffer in octets
|
* @ie_len: Length of ie buffer in octets
|
||||||
* Returns: 0 to indicate the frame was not processed or 1 if it was
|
* Returns: value indicating the type and status of the probe request
|
||||||
*/
|
*/
|
||||||
int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
enum p2p_probe_req_status
|
||||||
const u8 *bssid, const u8 *ie, size_t ie_len);
|
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
||||||
|
const u8 *bssid, const u8 *ie, size_t ie_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* p2p_rx_action - Report received Action frame
|
* p2p_rx_action - Report received Action frame
|
||||||
|
|
|
@ -25,6 +25,10 @@ struct wpas_dbus_priv {
|
||||||
struct wpa_global *global;
|
struct wpa_global *global;
|
||||||
u32 next_objid;
|
u32 next_objid;
|
||||||
int dbus_new_initialized;
|
int dbus_new_initialized;
|
||||||
|
|
||||||
|
#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP)
|
||||||
|
int dbus_noc_refcnt;
|
||||||
|
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DBUS_COMMON_I_H */
|
#endif /* DBUS_COMMON_I_H */
|
||||||
|
|
|
@ -31,6 +31,99 @@
|
||||||
#include "dbus_new_handlers_p2p.h"
|
#include "dbus_new_handlers_p2p.h"
|
||||||
#include "p2p/p2p.h"
|
#include "p2p/p2p.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_AP /* until needed by something else */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NameOwnerChanged handling
|
||||||
|
*
|
||||||
|
* Some services we provide allow an application to register for
|
||||||
|
* a signal that it needs. While it can also unregister, we must
|
||||||
|
* be prepared for the case where the application simply crashes
|
||||||
|
* and thus doesn't clean up properly. The way to handle this in
|
||||||
|
* DBus is to register for the NameOwnerChanged signal which will
|
||||||
|
* signal an owner change to NULL if the peer closes the socket
|
||||||
|
* for whatever reason.
|
||||||
|
*
|
||||||
|
* Handle this signal via a filter function whenever necessary.
|
||||||
|
* The code below also handles refcounting in case in the future
|
||||||
|
* there will be multiple instances of this subscription scheme.
|
||||||
|
*/
|
||||||
|
static const char wpas_dbus_noc_filter_str[] =
|
||||||
|
"interface=org.freedesktop.DBus,member=NameOwnerChanged";
|
||||||
|
|
||||||
|
|
||||||
|
static DBusHandlerResult noc_filter(DBusConnection *conn,
|
||||||
|
DBusMessage *message, void *data)
|
||||||
|
{
|
||||||
|
struct wpas_dbus_priv *priv = data;
|
||||||
|
|
||||||
|
if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
|
||||||
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
|
|
||||||
|
if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
|
||||||
|
"NameOwnerChanged")) {
|
||||||
|
const char *name;
|
||||||
|
const char *prev_owner;
|
||||||
|
const char *new_owner;
|
||||||
|
DBusError derr;
|
||||||
|
struct wpa_supplicant *wpa_s;
|
||||||
|
|
||||||
|
dbus_error_init(&derr);
|
||||||
|
|
||||||
|
if (!dbus_message_get_args(message, &derr,
|
||||||
|
DBUS_TYPE_STRING, &name,
|
||||||
|
DBUS_TYPE_STRING, &prev_owner,
|
||||||
|
DBUS_TYPE_STRING, &new_owner,
|
||||||
|
DBUS_TYPE_INVALID)) {
|
||||||
|
/* Ignore this error */
|
||||||
|
dbus_error_free(&derr);
|
||||||
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next)
|
||||||
|
{
|
||||||
|
if (wpa_s->preq_notify_peer != NULL &&
|
||||||
|
os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
|
||||||
|
(new_owner == NULL || os_strlen(new_owner) == 0)) {
|
||||||
|
/* probe request owner disconnected */
|
||||||
|
os_free(wpa_s->preq_notify_peer);
|
||||||
|
wpa_s->preq_notify_peer = NULL;
|
||||||
|
wpas_dbus_unsubscribe_noc(priv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv)
|
||||||
|
{
|
||||||
|
priv->dbus_noc_refcnt++;
|
||||||
|
if (priv->dbus_noc_refcnt > 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!dbus_connection_add_filter(priv->con, noc_filter, priv, NULL)) {
|
||||||
|
wpa_printf(MSG_ERROR, "dbus: failed to add filter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_bus_add_match(priv->con, wpas_dbus_noc_filter_str, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv)
|
||||||
|
{
|
||||||
|
priv->dbus_noc_refcnt--;
|
||||||
|
if (priv->dbus_noc_refcnt > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dbus_bus_remove_match(priv->con, wpas_dbus_noc_filter_str, NULL);
|
||||||
|
dbus_connection_remove_filter(priv->con, noc_filter, priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_AP */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wpas_dbus_signal_interface - Send a interface related event signal
|
* wpas_dbus_signal_interface - Send a interface related event signal
|
||||||
|
@ -2487,6 +2580,20 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
|
||||||
END_ARGS
|
END_ARGS
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
#ifdef CONFIG_AP
|
||||||
|
{ "SubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
|
||||||
|
(WPADBusMethodHandler) wpas_dbus_handler_subscribe_preq,
|
||||||
|
{
|
||||||
|
END_ARGS
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ "UnsubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
|
||||||
|
(WPADBusMethodHandler) wpas_dbus_handler_unsubscribe_preq,
|
||||||
|
{
|
||||||
|
END_ARGS
|
||||||
|
}
|
||||||
|
},
|
||||||
|
#endif /* CONFIG_AP */
|
||||||
{ NULL, NULL, NULL, { END_ARGS } }
|
{ NULL, NULL, NULL, { END_ARGS } }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2813,6 +2920,14 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
#ifdef CONFIG_AP
|
||||||
|
{ "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
|
||||||
|
{
|
||||||
|
{ "args", "a{sv}", ARG_OUT },
|
||||||
|
END_ARGS
|
||||||
|
}
|
||||||
|
},
|
||||||
|
#endif /* CONFIG_AP */
|
||||||
{ "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE,
|
{ "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE,
|
||||||
{
|
{
|
||||||
{ "certification", "a{sv}", ARG_OUT },
|
{ "certification", "a{sv}", ARG_OUT },
|
||||||
|
@ -2886,6 +3001,15 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
|
wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
|
||||||
wpa_s->dbus_new_path);
|
wpa_s->dbus_new_path);
|
||||||
|
|
||||||
|
#ifdef CONFIG_AP
|
||||||
|
if (wpa_s->preq_notify_peer) {
|
||||||
|
wpas_dbus_unsubscribe_noc(ctrl_iface);
|
||||||
|
os_free(wpa_s->preq_notify_peer);
|
||||||
|
wpa_s->preq_notify_peer = NULL;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_AP */
|
||||||
|
|
||||||
if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
|
if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
|
||||||
wpa_s->dbus_new_path))
|
wpa_s->dbus_new_path))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -115,6 +115,17 @@ enum wpas_dbus_bss_prop {
|
||||||
#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
|
#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
|
||||||
WPAS_DBUS_NEW_INTERFACE ".BlobUnknown"
|
WPAS_DBUS_NEW_INTERFACE ".BlobUnknown"
|
||||||
|
|
||||||
|
#define WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE \
|
||||||
|
WPAS_DBUS_NEW_INTERFACE ".SubscriptionInUse"
|
||||||
|
#define WPAS_DBUS_ERROR_NO_SUBSCRIPTION \
|
||||||
|
WPAS_DBUS_NEW_INTERFACE ".NoSubscription"
|
||||||
|
#define WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM \
|
||||||
|
WPAS_DBUS_NEW_INTERFACE ".SubscriptionNotYou"
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv);
|
||||||
|
void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv);
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
|
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
|
||||||
|
|
||||||
|
@ -210,6 +221,9 @@ void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
|
||||||
int depth, const char *subject,
|
int depth, const char *subject,
|
||||||
const char *cert_hash,
|
const char *cert_hash,
|
||||||
const struct wpabuf *cert);
|
const struct wpabuf *cert);
|
||||||
|
void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
|
||||||
|
const u8 *addr, const u8 *dst, const u8 *bssid,
|
||||||
|
const u8 *ie, size_t ie_len, u32 ssi_signal);
|
||||||
|
|
||||||
#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
|
#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
|
||||||
|
|
||||||
|
@ -467,6 +481,14 @@ static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
|
||||||
|
const u8 *addr, const u8 *dst,
|
||||||
|
const u8 *bssid,
|
||||||
|
const u8 *ie, size_t ie_len,
|
||||||
|
u32 ssi_signal)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
|
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
|
||||||
|
|
||||||
#endif /* CTRL_IFACE_DBUS_H_NEW */
|
#endif /* CTRL_IFACE_DBUS_H_NEW */
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "dbus_new.h"
|
#include "dbus_new.h"
|
||||||
#include "dbus_new_handlers.h"
|
#include "dbus_new_handlers.h"
|
||||||
#include "dbus_dict_helpers.h"
|
#include "dbus_dict_helpers.h"
|
||||||
|
#include "dbus_common_i.h"
|
||||||
|
|
||||||
extern int wpa_debug_level;
|
extern int wpa_debug_level;
|
||||||
extern int wpa_debug_show_keys;
|
extern int wpa_debug_show_keys;
|
||||||
|
@ -3412,3 +3413,139 @@ dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
|
||||||
dbus_message_iter_recurse(iter, &variant_iter);
|
dbus_message_iter_recurse(iter, &variant_iter);
|
||||||
return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
|
return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_AP
|
||||||
|
|
||||||
|
DBusMessage * wpas_dbus_handler_subscribe_preq(
|
||||||
|
DBusMessage *message, struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
struct wpas_dbus_priv *priv = wpa_s->global->dbus;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
if (wpa_s->preq_notify_peer != NULL) {
|
||||||
|
if (os_strcmp(dbus_message_get_sender(message),
|
||||||
|
wpa_s->preq_notify_peer) == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return dbus_message_new_error(message,
|
||||||
|
WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
|
||||||
|
"Another application is already subscribed");
|
||||||
|
}
|
||||||
|
|
||||||
|
name = os_strdup(dbus_message_get_sender(message));
|
||||||
|
if (!name)
|
||||||
|
return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
|
||||||
|
"out of memory");
|
||||||
|
|
||||||
|
wpa_s->preq_notify_peer = name;
|
||||||
|
|
||||||
|
/* Subscribe to clean up if application closes socket */
|
||||||
|
wpas_dbus_subscribe_noc(priv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Double-check it's still alive to make sure that we didn't
|
||||||
|
* miss the NameOwnerChanged signal, e.g. while strdup'ing.
|
||||||
|
*/
|
||||||
|
if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
|
||||||
|
/*
|
||||||
|
* Application no longer exists, clean up.
|
||||||
|
* The return value is irrelevant now.
|
||||||
|
*
|
||||||
|
* Need to check if the NameOwnerChanged handling
|
||||||
|
* already cleaned up because we have processed
|
||||||
|
* DBus messages while checking if the name still
|
||||||
|
* has an owner.
|
||||||
|
*/
|
||||||
|
if (!wpa_s->preq_notify_peer)
|
||||||
|
return NULL;
|
||||||
|
os_free(wpa_s->preq_notify_peer);
|
||||||
|
wpa_s->preq_notify_peer = NULL;
|
||||||
|
wpas_dbus_unsubscribe_noc(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DBusMessage * wpas_dbus_handler_unsubscribe_preq(
|
||||||
|
DBusMessage *message, struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
struct wpas_dbus_priv *priv = wpa_s->global->dbus;
|
||||||
|
|
||||||
|
if (!wpa_s->preq_notify_peer)
|
||||||
|
return dbus_message_new_error(message,
|
||||||
|
WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
|
||||||
|
"Not subscribed");
|
||||||
|
|
||||||
|
if (os_strcmp(wpa_s->preq_notify_peer,
|
||||||
|
dbus_message_get_sender(message)))
|
||||||
|
return dbus_message_new_error(message,
|
||||||
|
WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
|
||||||
|
"Can't unsubscribe others");
|
||||||
|
|
||||||
|
os_free(wpa_s->preq_notify_peer);
|
||||||
|
wpa_s->preq_notify_peer = NULL;
|
||||||
|
wpas_dbus_unsubscribe_noc(priv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
|
||||||
|
const u8 *addr, const u8 *dst, const u8 *bssid,
|
||||||
|
const u8 *ie, size_t ie_len, u32 ssi_signal)
|
||||||
|
{
|
||||||
|
DBusMessage *msg;
|
||||||
|
DBusMessageIter iter, dict_iter;
|
||||||
|
struct wpas_dbus_priv *priv = wpa_s->global->dbus;
|
||||||
|
|
||||||
|
/* Do nothing if the control interface is not turned on */
|
||||||
|
if (priv == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (wpa_s->preq_notify_peer == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
|
||||||
|
WPAS_DBUS_NEW_IFACE_INTERFACE,
|
||||||
|
"ProbeRequest");
|
||||||
|
if (msg == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
|
||||||
|
|
||||||
|
dbus_message_iter_init_append(msg, &iter);
|
||||||
|
|
||||||
|
if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
|
||||||
|
goto fail;
|
||||||
|
if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
|
||||||
|
(const char *) addr,
|
||||||
|
ETH_ALEN))
|
||||||
|
goto fail;
|
||||||
|
if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
|
||||||
|
(const char *) dst,
|
||||||
|
ETH_ALEN))
|
||||||
|
goto fail;
|
||||||
|
if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
|
||||||
|
(const char *) bssid,
|
||||||
|
ETH_ALEN))
|
||||||
|
goto fail;
|
||||||
|
if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
|
||||||
|
(const char *) ie,
|
||||||
|
ie_len))
|
||||||
|
goto fail;
|
||||||
|
if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
|
||||||
|
ssi_signal))
|
||||||
|
goto fail;
|
||||||
|
if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
dbus_connection_send(priv->con, msg, NULL);
|
||||||
|
goto out;
|
||||||
|
fail:
|
||||||
|
wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
|
||||||
|
out:
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_AP */
|
||||||
|
|
|
@ -266,4 +266,9 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
|
||||||
DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
|
DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
|
||||||
const char *arg);
|
const char *arg);
|
||||||
|
|
||||||
|
DBusMessage * wpas_dbus_handler_subscribe_preq(
|
||||||
|
DBusMessage *message, struct wpa_supplicant *wpa_s);
|
||||||
|
DBusMessage * wpas_dbus_handler_unsubscribe_preq(
|
||||||
|
DBusMessage *message, struct wpa_supplicant *wpa_s);
|
||||||
|
|
||||||
#endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */
|
#endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */
|
||||||
|
|
|
@ -2309,15 +2309,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
|
ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
|
||||||
data->rx_from_unknown.wds);
|
data->rx_from_unknown.wds);
|
||||||
break;
|
break;
|
||||||
case EVENT_RX_MGMT:
|
case EVENT_RX_MGMT: {
|
||||||
|
u16 fc, stype;
|
||||||
|
const struct ieee80211_mgmt *mgmt;
|
||||||
|
|
||||||
|
mgmt = (const struct ieee80211_mgmt *)
|
||||||
|
data->rx_mgmt.frame;
|
||||||
|
fc = le_to_host16(mgmt->frame_control);
|
||||||
|
stype = WLAN_FC_GET_STYPE(fc);
|
||||||
|
|
||||||
if (wpa_s->ap_iface == NULL) {
|
if (wpa_s->ap_iface == NULL) {
|
||||||
#ifdef CONFIG_P2P
|
#ifdef CONFIG_P2P
|
||||||
u16 fc, stype;
|
|
||||||
const struct ieee80211_mgmt *mgmt;
|
|
||||||
mgmt = (const struct ieee80211_mgmt *)
|
|
||||||
data->rx_mgmt.frame;
|
|
||||||
fc = le_to_host16(mgmt->frame_control);
|
|
||||||
stype = WLAN_FC_GET_STYPE(fc);
|
|
||||||
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
|
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
|
||||||
data->rx_mgmt.frame_len > 24) {
|
data->rx_mgmt.frame_len > 24) {
|
||||||
const u8 *src = mgmt->sa;
|
const u8 *src = mgmt->sa;
|
||||||
|
@ -2336,8 +2338,23 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
"management frame in non-AP mode");
|
"management frame in non-AP mode");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
|
||||||
|
data->rx_mgmt.frame_len > 24) {
|
||||||
|
const u8 *ie = mgmt->u.probe_req.variable;
|
||||||
|
size_t ie_len = data->rx_mgmt.frame_len -
|
||||||
|
(mgmt->u.probe_req.variable -
|
||||||
|
data->rx_mgmt.frame);
|
||||||
|
|
||||||
|
wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
|
||||||
|
mgmt->bssid, ie, ie_len,
|
||||||
|
data->rx_mgmt.ssi_signal);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ap_mgmt_rx(wpa_s, &data->rx_mgmt);
|
ap_mgmt_rx(wpa_s, &data->rx_mgmt);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
#endif /* CONFIG_AP */
|
#endif /* CONFIG_AP */
|
||||||
case EVENT_RX_ACTION:
|
case EVENT_RX_ACTION:
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
|
wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
|
||||||
|
|
62
wpa_supplicant/examples/dbus-listen-preq.py
Executable file
62
wpa_supplicant/examples/dbus-listen-preq.py
Executable file
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import dbus
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import gobject
|
||||||
|
from dbus.mainloop.glib import DBusGMainLoop
|
||||||
|
|
||||||
|
WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1"
|
||||||
|
WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1"
|
||||||
|
WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1"
|
||||||
|
WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface"
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print "Usage: %s <ifname>" % sys.argv[0]
|
||||||
|
print "Press Ctrl-C to stop"
|
||||||
|
|
||||||
|
def ProbeRequest(args):
|
||||||
|
if 'addr' in args:
|
||||||
|
print '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
|
||||||
|
if 'dst' in args:
|
||||||
|
print '-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
|
||||||
|
if 'bssid' in args:
|
||||||
|
print '(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
|
||||||
|
if 'signal' in args:
|
||||||
|
print 'signal:%d' % args['signal'],
|
||||||
|
if 'ies' in args:
|
||||||
|
print 'have IEs (%d bytes)' % len(args['ies']),
|
||||||
|
print ''
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
global bus
|
||||||
|
global wpas_obj
|
||||||
|
global if_obj
|
||||||
|
global p2p_iface
|
||||||
|
|
||||||
|
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||||
|
|
||||||
|
bus = dbus.SystemBus()
|
||||||
|
wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
|
||||||
|
|
||||||
|
# Print list of i/f if no one is specified
|
||||||
|
if (len(sys.argv) < 2) :
|
||||||
|
usage()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
|
||||||
|
|
||||||
|
ifname = sys.argv[1]
|
||||||
|
|
||||||
|
path = wpas.GetInterface(ifname)
|
||||||
|
|
||||||
|
if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
|
||||||
|
iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE)
|
||||||
|
|
||||||
|
bus.add_signal_receiver(ProbeRequest,
|
||||||
|
dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
|
||||||
|
signal_name="ProbeRequest")
|
||||||
|
|
||||||
|
iface.SubscribeProbeReq()
|
||||||
|
|
||||||
|
gobject.MainLoop().run()
|
|
@ -602,3 +602,13 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
|
||||||
/* notify the new DBus API */
|
/* notify the new DBus API */
|
||||||
wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
|
wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_notify_preq(struct wpa_supplicant *wpa_s,
|
||||||
|
const u8 *addr, const u8 *dst, const u8 *bssid,
|
||||||
|
const u8 *ie, size_t ie_len, u32 ssi_signal)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_AP
|
||||||
|
wpas_dbus_signal_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal);
|
||||||
|
#endif /* CONFIG_AP */
|
||||||
|
}
|
||||||
|
|
|
@ -121,5 +121,8 @@ void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
|
||||||
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
|
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
|
||||||
const char *subject, const char *cert_hash,
|
const char *subject, const char *cert_hash,
|
||||||
const struct wpabuf *cert);
|
const struct wpabuf *cert);
|
||||||
|
void wpas_notify_preq(struct wpa_supplicant *wpa_s,
|
||||||
|
const u8 *addr, const u8 *dst, const u8 *bssid,
|
||||||
|
const u8 *ie, size_t ie_len, u32 ssi_signal);
|
||||||
|
|
||||||
#endif /* NOTIFY_H */
|
#endif /* NOTIFY_H */
|
||||||
|
|
|
@ -3704,8 +3704,20 @@ int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
|
||||||
if (wpa_s->global->p2p == NULL)
|
if (wpa_s->global->p2p == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
|
switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
|
||||||
ie, ie_len);
|
ie, ie_len)) {
|
||||||
|
case P2P_PREQ_NOT_P2P:
|
||||||
|
wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
|
||||||
|
ssi_signal);
|
||||||
|
/* fall through */
|
||||||
|
case P2P_PREQ_MALFORMED:
|
||||||
|
case P2P_PREQ_NOT_LISTEN:
|
||||||
|
case P2P_PREQ_NOT_PROCESSED:
|
||||||
|
default: /* make gcc happy */
|
||||||
|
return 0;
|
||||||
|
case P2P_PREQ_PROCESSED:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -265,6 +265,9 @@ struct wpa_supplicant {
|
||||||
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
|
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
|
||||||
char *dbus_new_path;
|
char *dbus_new_path;
|
||||||
char *dbus_groupobj_path;
|
char *dbus_groupobj_path;
|
||||||
|
#ifdef CONFIG_AP
|
||||||
|
char *preq_notify_peer;
|
||||||
|
#endif /* CONFIG_AP */
|
||||||
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
|
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
|
||||||
char bridge_ifname[16];
|
char bridge_ifname[16];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue