summaryrefslogtreecommitdiff
path: root/src/p2p
diff options
context:
space:
mode:
authorAndrew Shadura <andrewsh@debian.org>2016-07-20 19:07:58 +0200
committerAndrew Shadura <andrewsh@debian.org>2016-07-20 19:07:58 +0200
commit379fee4d2cb49ebda46d4546dc697dee4a9d9352 (patch)
tree1cc5c21d2a82caaa0ad0c3f88870479ddccbf67e /src/p2p
parent4442ea526434508f455e85290eabc0cc4523b5dd (diff)
Imported Upstream version 1.0~rc3
Diffstat (limited to 'src/p2p')
-rw-r--r--src/p2p/p2p.c122
-rw-r--r--src/p2p/p2p.h59
-rw-r--r--src/p2p/p2p_go_neg.c16
-rw-r--r--src/p2p/p2p_i.h11
-rw-r--r--src/p2p/p2p_invitation.c2
-rw-r--r--src/p2p/p2p_pd.c14
6 files changed, 212 insertions, 12 deletions
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index caff7d7..3bcbea6 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -142,6 +142,34 @@ static const char * p2p_state_txt(int state)
}
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
+{
+ struct p2p_device *dev = NULL;
+
+ if (!addr || !p2p)
+ return 0;
+
+ dev = p2p_get_device(p2p, addr);
+ if (dev)
+ return dev->wps_prov_info;
+ else
+ return 0;
+}
+
+
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr)
+{
+ struct p2p_device *dev = NULL;
+
+ if (!addr || !p2p)
+ return;
+
+ dev = p2p_get_device(p2p, addr);
+ if (dev)
+ dev->wps_prov_info = 0;
+}
+
+
void p2p_set_state(struct p2p_data *p2p, int new_state)
{
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
@@ -796,7 +824,7 @@ static void p2p_search(struct p2p_data *p2p)
if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id) < 0) {
+ p2p->find_dev_id)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Scan request failed");
p2p_continue_find(p2p);
@@ -1002,11 +1030,21 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
p2p->go_neg_peer = NULL;
p2p->sd_peer = NULL;
p2p->invite_peer = NULL;
+ p2p_stop_listen_for_freq(p2p, freq);
+}
+
+
+void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
+{
if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip stop_listen "
"since we are on correct channel for response");
return;
}
+ if (p2p->in_listen) {
+ p2p->in_listen = 0;
+ p2p_clear_timeout(p2p);
+ }
if (p2p->drv_in_listen) {
/*
* The driver may not deliver callback to p2p_listen_end()
@@ -2068,6 +2106,35 @@ int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end)
}
+int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr)
+{
+ struct wpabuf *p2p_ie;
+ struct p2p_message msg;
+ int ret = -1;
+
+ p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+ P2P_IE_VENDOR_TYPE);
+ if (p2p_ie == NULL)
+ return -1;
+ os_memset(&msg, 0, sizeof(msg));
+ if (p2p_parse_p2p_ie(p2p_ie, &msg)) {
+ wpabuf_free(p2p_ie);
+ return -1;
+ }
+
+ if (msg.p2p_device_addr) {
+ os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN);
+ ret = 0;
+ } else if (msg.device_id) {
+ os_memcpy(dev_addr, msg.device_id, ETH_ALEN);
+ ret = 0;
+ }
+
+ wpabuf_free(p2p_ie);
+ return ret;
+}
+
+
static void p2p_clear_go_neg(struct p2p_data *p2p)
{
p2p->go_neg_peer = NULL;
@@ -2142,6 +2209,16 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
p2p->cfg->model_number = os_strdup(cfg->model_number);
if (cfg->serial_number)
p2p->cfg->serial_number = os_strdup(cfg->serial_number);
+ if (cfg->pref_chan) {
+ p2p->cfg->pref_chan = os_malloc(cfg->num_pref_chan *
+ sizeof(struct p2p_channel));
+ if (p2p->cfg->pref_chan) {
+ os_memcpy(p2p->cfg->pref_chan, cfg->pref_chan,
+ cfg->num_pref_chan *
+ sizeof(struct p2p_channel));
+ } else
+ p2p->cfg->num_pref_chan = 0;
+ }
p2p->min_disc_int = 1;
p2p->max_disc_int = 3;
@@ -2176,6 +2253,7 @@ void p2p_deinit(struct p2p_data *p2p)
os_free(p2p->cfg->model_name);
os_free(p2p->cfg->model_number);
os_free(p2p->cfg->serial_number);
+ os_free(p2p->cfg->pref_chan);
os_free(p2p->groups);
wpabuf_free(p2p->sd_resp);
os_free(p2p->after_scan_tx);
@@ -2187,11 +2265,7 @@ void p2p_deinit(struct p2p_data *p2p)
void p2p_flush(struct p2p_data *p2p)
{
struct p2p_device *dev, *prev;
- p2p_clear_timeout(p2p);
- p2p_set_state(p2p, P2P_IDLE);
- p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
- p2p->go_neg_peer = NULL;
- eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+ p2p_stop_find(p2p);
dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device,
list) {
dl_list_del(&dev->list);
@@ -2797,6 +2871,20 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
p2p_connect_send(p2p, p2p->go_neg_peer);
return 1;
} else if (p2p->state == P2P_SEARCH) {
+ if (p2p->p2p_scan_running) {
+ /*
+ * Search is already in progress. This can happen if
+ * an Action frame RX is reported immediately after
+ * the end of a remain-on-channel operation and the
+ * response frame to that is sent using an offchannel
+ * operation while in p2p_find. Avoid an attempt to
+ * restart a scan here.
+ */
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan "
+ "already in progress - do not try to start a "
+ "new one");
+ return 1;
+ }
p2p_search(p2p);
return 1;
}
@@ -3621,6 +3709,28 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
}
+int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
+ const struct p2p_channel *pref_chan)
+{
+ struct p2p_channel *n;
+
+ if (pref_chan) {
+ n = os_malloc(num_pref_chan * sizeof(struct p2p_channel));
+ if (n == NULL)
+ return -1;
+ os_memcpy(n, pref_chan,
+ num_pref_chan * sizeof(struct p2p_channel));
+ } else
+ n = NULL;
+
+ os_free(p2p->cfg->pref_chan);
+ p2p->cfg->pref_chan = n;
+ p2p->cfg->num_pref_chan = num_pref_chan;
+
+ return 0;
+}
+
+
int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
u8 *iface_addr)
{
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index ace69c3..75d4739 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -224,6 +224,11 @@ enum p2p_prov_disc_status {
P2P_PROV_DISC_REJECTED,
};
+struct p2p_channel {
+ u8 op_class;
+ u8 chan;
+};
+
/**
* struct p2p_config - P2P configuration
*
@@ -271,6 +276,16 @@ struct p2p_config {
struct p2p_channels channels;
/**
+ * num_pref_chan - Number of pref_chan entries
+ */
+ unsigned int num_pref_chan;
+
+ /**
+ * pref_chan - Preferred channels for GO Negotiation
+ */
+ struct p2p_channel *pref_chan;
+
+ /**
* pri_dev_type - Primary Device Type (see WPS)
*/
u8 pri_dev_type[8];
@@ -1051,6 +1066,28 @@ void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr);
*/
void p2p_group_formation_failed(struct p2p_data *p2p);
+/**
+ * p2p_get_provisioning_info - Get any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @addr: Peer P2P Device Address
+ * Returns: WPS provisioning information (WPS config method) or 0 if no
+ * information is available
+ *
+ * This function is used to retrieve stored WPS provisioning info for the given
+ * peer.
+ */
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr);
+
+/**
+ * p2p_clear_provisioning_info - Clear any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @iface_addr: Peer P2P Device Address
+ *
+ * This function is used to clear stored WPS provisioning info for the given
+ * peer.
+ */
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr);
+
/* Event notifications from lower layer driver operations */
@@ -1355,6 +1392,15 @@ int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end);
int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end);
/**
+ * p2p_parse_dev_addr - Parse P2P Device Address from P2P IE(s)
+ * @ies: Information elements from scan results
+ * @ies_len: ies buffer length in octets
+ * @dev_addr: Buffer for returning P2P Device Address
+ * Returns: 0 on success or -1 if P2P Device Address could not be parsed
+ */
+int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr);
+
+/**
* p2p_assoc_req_ie - Build P2P IE for (Re)Association Request frame
* @p2p: P2P module context from p2p_init()
* @bssid: BSSID
@@ -1481,9 +1527,6 @@ void p2p_set_cross_connect(struct p2p_data *p2p, int enabled);
int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr);
-int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
- const u8 *ies, size_t ies_len);
-
/**
* p2p_set_intra_bss_dist - Set intra BSS distribution
* @p2p: P2P module context from p2p_init()
@@ -1586,6 +1629,16 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
int cfg_op_channel);
/**
+ * p2p_set_pref_chan - Set P2P preferred channel list
+ * @p2p: P2P module context from p2p_init()
+ * @num_pref_chan: Number of entries in pref_chan list
+ * @pref_chan: Preferred channels or %NULL to remove preferences
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
+ const struct p2p_channel *pref_chan);
+
+/**
* p2p_in_progress - Check whether a P2P operation is progress
* @p2p: P2P module context from p2p_init()
* Returns: 0 if P2P module is idle or 1 if an operation is in progress
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index eb85f51..f83d3de 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -302,6 +302,7 @@ static void p2p_reselect_channel(struct p2p_data *p2p,
struct p2p_reg_class *cl;
int freq;
u8 op_reg_class, op_channel;
+ unsigned int i;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
"channel (reg_class %u channel %u) not acceptable to the "
@@ -334,6 +335,21 @@ static void p2p_reselect_channel(struct p2p_data *p2p,
return;
}
+ /* Select channel with highest preference if the peer supports it */
+ for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
+ if (p2p_channels_includes(intersection,
+ p2p->cfg->pref_chan[i].op_class,
+ p2p->cfg->pref_chan[i].chan)) {
+ p2p->op_reg_class = p2p->cfg->pref_chan[i].op_class;
+ p2p->op_channel = p2p->cfg->pref_chan[i].chan;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick "
+ "highest preferred chnnel (op_class %u "
+ "channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
+ }
+ }
+
/*
* Fall back to whatever is included in the channel intersection since
* no better options seems to be available.
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 82df24e..d052a03 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -71,6 +71,14 @@ struct p2p_device {
*/
u16 req_config_methods;
+ /**
+ * wps_prov_info - Stored provisioning WPS config method
+ *
+ * This is used to store pending WPS config method between Provisioning
+ * Discovery and connection to a running group.
+ */
+ u16 wps_prov_info;
+
#define P2P_DEV_PROBE_REQ_ONLY BIT(0)
#define P2P_DEV_REPORTED BIT(1)
#define P2P_DEV_NOT_YET_READY BIT(2)
@@ -649,6 +657,8 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
struct p2p_message *msg);
void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
struct p2p_device *dev, struct p2p_message *msg);
+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
+ const u8 *ies, size_t ies_len);
struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
const u8 *addr);
@@ -663,5 +673,6 @@ void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len);
int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
size_t len, unsigned int wait_time);
+void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
#endif /* P2P_I_H */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index bb2767d..016c572 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -350,6 +350,8 @@ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
req = p2p_build_invitation_req(p2p, dev, go_dev_addr);
if (req == NULL)
return -1;
+ if (p2p->state != P2P_IDLE)
+ p2p_stop_listen_for_freq(p2p, freq);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Sending Invitation Request");
p2p_set_state(p2p, P2P_INVITE);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 0f06cbd..8eced26 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -267,6 +267,10 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
}
+
+ /* Store the provisioning info */
+ dev->wps_prov_info = msg.wps_config_methods;
+
p2p_parse_free(&msg);
out:
@@ -318,6 +322,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
if (req == NULL)
return -1;
+ if (p2p->state != P2P_IDLE)
+ p2p_stop_listen_for_freq(p2p, freq);
p2p->pending_action_state = P2P_PENDING_PD;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
@@ -356,15 +362,17 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
if (config_methods == 0)
return -1;
+ /* Reset provisioning info */
+ dev->wps_prov_info = 0;
+
dev->req_config_methods = config_methods;
if (join)
dev->flags |= P2P_DEV_PD_FOR_JOIN;
else
dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
- if (p2p->go_neg_peer ||
- (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
- p2p->state != P2P_LISTEN_ONLY)) {
+ if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
+ p2p->state != P2P_LISTEN_ONLY) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other "
"operations; postpone Provision Discovery Request "
"with " MACSTR " (config methods 0x%x)",