Browse Source

P2P: Wait until ongoing scan completes before starting P2P find

The P2P_FIND command was failing if it was issued at the moment when
a scan operation was in progress. Avoid returning failure in this
case by scheduling the P2P find to start once the ongoing scan is
completed.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
Jouni Malinen 13 years ago
parent
commit
39185dfa54
6 changed files with 61 additions and 1 deletions
  1. 25 0
      src/p2p/p2p.c
  2. 7 0
      src/p2p/p2p.h
  3. 6 0
      src/p2p/p2p_i.h
  4. 12 0
      wpa_supplicant/events.c
  5. 9 1
      wpa_supplicant/p2p_supplicant.c
  6. 2 0
      wpa_supplicant/wpa_supplicant_i.h

+ 25 - 0
src/p2p/p2p.c

@@ -106,6 +106,8 @@ static const char * p2p_state_txt(int state)
 		return "INVITE";
 	case P2P_INVITE_LISTEN:
 		return "INVITE_LISTEN";
+	case P2P_SEARCH_WHEN_READY:
+		return "SEARCH_WHEN_READY";
 	default:
 		return "?";
 	}
@@ -878,6 +880,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
 	p2p_device_clear_reported(p2p);
 	p2p_set_state(p2p, P2P_SEARCH);
 	eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+	p2p->last_p2p_find_timeout = timeout;
 	if (timeout)
 		eloop_register_timeout(timeout, 0, p2p_find_timeout,
 				       p2p, NULL);
@@ -903,6 +906,13 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
 		eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
 		eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
 				       p2p, NULL);
+	} else if (res == 1) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
+			"p2p_scan at this point - will try again after "
+			"previous scan completes");
+		res = 0;
+		p2p_set_state(p2p, P2P_SEARCH_WHEN_READY);
+		eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	} else {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
 			"p2p_scan");
@@ -914,6 +924,19 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
 }
 
 
+int p2p_other_scan_completed(struct p2p_data *p2p)
+{
+	if (p2p->state != P2P_SEARCH_WHEN_READY)
+		return 0;
+	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
+		"now that previous scan was completed");
+	if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
+		     p2p->num_req_dev_types, p2p->req_dev_types) < 0)
+		return 0;
+	return 1;
+}
+
+
 void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
 {
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
@@ -2947,6 +2970,8 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
 	case P2P_INVITE_LISTEN:
 		p2p_timeout_invite_listen(p2p);
 		break;
+	case P2P_SEARCH_WHEN_READY:
+		break;
 	}
 }
 

+ 7 - 0
src/p2p/p2p.h

@@ -1542,4 +1542,11 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
  */
 int p2p_in_progress(struct p2p_data *p2p);
 
+/**
+ * p2p_other_scan_completed - Notify completion of non-P2P scan
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation was started
+ */
+int p2p_other_scan_completed(struct p2p_data *p2p);
+
 #endif /* P2P_H */

+ 6 - 0
src/p2p/p2p_i.h

@@ -201,6 +201,11 @@ struct p2p_data {
 		 * P2P_INVITE_LISTEN - Listen during Invite
 		 */
 		P2P_INVITE_LISTEN,
+
+		/**
+		 * P2P_SEARCH_WHEN_READY - Waiting to start Search
+		 */
+		P2P_SEARCH_WHEN_READY,
 	} state;
 
 	/**
@@ -355,6 +360,7 @@ struct p2p_data {
 	int inv_persistent;
 
 	enum p2p_discovery_type find_type;
+	unsigned int last_p2p_find_timeout;
 	u8 last_prog_scan_class;
 	u8 last_prog_scan_chan;
 	int p2p_scan_running;

+ 12 - 0
wpa_supplicant/events.c

@@ -1009,6 +1009,18 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 
 	wpa_supplicant_notify_scanning(wpa_s, 0);
 
+#ifdef CONFIG_P2P
+	if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL) {
+		wpa_s->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"stopped scan processing");
+			return -1;
+		}
+	}
+#endif /* CONFIG_P2P */
+
 	scan_res = wpa_supplicant_get_scan_results(wpa_s,
 						   data ? &data->scan_info :
 						   NULL, 1);

+ 9 - 1
wpa_supplicant/p2p_supplicant.c

@@ -94,6 +94,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
 	struct wpabuf *wps_ie, *ies;
 	int social_channels[] = { 2412, 2437, 2462, 0, 0 };
 	size_t ielen;
+	int was_in_p2p_scan;
 
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
@@ -144,13 +145,19 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
 		break;
 	}
 
+	was_in_p2p_scan = wpa_s->scan_res_handler == wpas_p2p_scan_res_handler;
 	wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
 	ret = wpa_drv_scan(wpa_s, &params);
 
 	wpabuf_free(ies);
 
-	if (ret < 0)
+	if (ret) {
 		wpa_s->scan_res_handler = NULL;
+		if (wpa_s->scanning || was_in_p2p_scan) {
+			wpa_s->p2p_cb_on_scan_complete = 1;
+			ret = 1;
+		}
+	}
 
 	return ret;
 }
@@ -3351,6 +3358,7 @@ void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
 	wpa_s->p2p_long_listen = 0;
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+	wpa_s->p2p_cb_on_scan_complete = 0;
 
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
 		wpa_drv_p2p_stop_find(wpa_s);

+ 2 - 0
wpa_supplicant/wpa_supplicant_i.h

@@ -476,6 +476,8 @@ struct wpa_supplicant {
 		P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
 		P2P_GROUP_REMOVAL_UNAVAILABLE
 	} removal_reason;
+
+	unsigned int p2p_cb_on_scan_complete:1;
 #endif /* CONFIG_P2P */
 
 	struct wpa_ssid *bgscan_ssid;