blob: 0827f354b62b99c21cc582d875122d5e508888de [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * wpa_supplicant - P2P
3 * Copyright (c) 2009-2010, Atheros Communications
4 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "eloop.h"
13#include "common/ieee802_11_common.h"
14#include "common/ieee802_11_defs.h"
15#include "common/wpa_ctrl.h"
16#include "wps/wps_i.h"
17#include "p2p/p2p.h"
18#include "ap/hostapd.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080019#include "ap/ap_config.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070020#include "ap/p2p_hostapd.h"
Jouni Malinen75ecf522011-06-27 15:19:46 -070021#include "eapol_supp/eapol_supp_sm.h"
22#include "rsn_supp/wpa.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070023#include "wpa_supplicant_i.h"
24#include "driver_i.h"
25#include "ap.h"
26#include "config_ssid.h"
27#include "config.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070028#include "notify.h"
29#include "scan.h"
30#include "bss.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080031#include "offchannel.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070032#include "wps_supplicant.h"
33#include "p2p_supplicant.h"
34
35
36/*
37 * How many times to try to scan to find the GO before giving up on join
38 * request.
39 */
40#define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
41
Dmitry Shmidt04949592012-07-19 12:16:46 -070042#define P2P_AUTO_PD_SCAN_ATTEMPTS 5
43
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080044#ifndef P2P_MAX_CLIENT_IDLE
45/*
46 * How many seconds to try to reconnect to the GO when connection in P2P client
47 * role has been lost.
48 */
Dmitry Shmidt98f9e762012-05-30 11:18:46 -070049#ifdef ANDROID_P2P
50#define P2P_MAX_CLIENT_IDLE 20
51#else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080052#define P2P_MAX_CLIENT_IDLE 10
Dmitry Shmidt98f9e762012-05-30 11:18:46 -070053#endif /* ANDROID_P2P */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080054#endif /* P2P_MAX_CLIENT_IDLE */
55
Dmitry Shmidt04949592012-07-19 12:16:46 -070056#ifndef P2P_MAX_INITIAL_CONN_WAIT
57/*
58 * How many seconds to wait for initial 4-way handshake to get completed after
59 * WPS provisioning step.
60 */
61#define P2P_MAX_INITIAL_CONN_WAIT 10
62#endif /* P2P_MAX_INITIAL_CONN_WAIT */
63
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070064#ifndef P2P_CONCURRENT_SEARCH_DELAY
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070065#define P2P_CONCURRENT_SEARCH_DELAY 500
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070066#endif /* P2P_CONCURRENT_SEARCH_DELAY */
67
Dmitry Shmidt34af3062013-07-11 10:46:32 -070068#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
69
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070070enum p2p_group_removal_reason {
71 P2P_GROUP_REMOVAL_UNKNOWN,
72 P2P_GROUP_REMOVAL_SILENT,
73 P2P_GROUP_REMOVAL_FORMATION_FAILED,
74 P2P_GROUP_REMOVAL_REQUESTED,
75 P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
76 P2P_GROUP_REMOVAL_UNAVAILABLE,
77 P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
78#ifdef ANDROID_P2P
79 P2P_GROUP_REMOVAL_FREQ_CONFLICT
80#endif
81};
82
Jouni Malinendc7b7132012-09-14 12:53:47 -070083
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070084static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx);
85static struct wpa_supplicant *
86wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
87 int go);
88static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -070089static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070090static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
91static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
Dmitry Shmidt04949592012-07-19 12:16:46 -070092 const u8 *dev_addr, enum p2p_wps_method wps_method,
93 int auto_join);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070094static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
95static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
96static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
97static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
Dmitry Shmidtf8623282013-02-20 14:34:59 -080098static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
99 void *timeout_ctx);
Dmitry Shmidt1cf45732013-04-29 17:36:45 -0700100#ifdef ANDROID_P2P
101static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
102#endif
Dmitry Shmidt04949592012-07-19 12:16:46 -0700103static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
104 int group_added);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800105static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700106
107
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -0700108/*
109 * Get the number of concurrent channels that the HW can operate, but that are
110 * currently not in use by any of the wpa_supplicant interfaces.
111 */
112static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s)
113{
114 int *freqs;
115 int num;
116
117 freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
118 if (!freqs)
119 return -1;
120
121 num = get_shared_radio_freqs(wpa_s, freqs,
122 wpa_s->num_multichan_concurrent);
123 os_free(freqs);
124
125 return wpa_s->num_multichan_concurrent - num;
126}
127
128
129/*
130 * Get the frequencies that are currently in use by one or more of the virtual
131 * interfaces, and that are also valid for P2P operation.
132 */
133static int wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s,
134 int *p2p_freqs, unsigned int len)
135{
136 int *freqs;
137 unsigned int num, i, j;
138
139 freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
140 if (!freqs)
141 return -1;
142
143 num = get_shared_radio_freqs(wpa_s, freqs,
144 wpa_s->num_multichan_concurrent);
145
146 os_memset(p2p_freqs, 0, sizeof(int) * len);
147
148 for (i = 0, j = 0; i < num && j < len; i++) {
149 if (p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
150 p2p_freqs[j++] = freqs[i];
151 }
152
153 os_free(freqs);
154
155 return j;
156}
157
158
Dmitry Shmidt700a1372013-03-15 14:14:44 -0700159static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s,
160 int freq)
161{
162 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
163 return;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -0700164 if (freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
165 wpas_p2p_num_unused_channels(wpa_s) > 0 &&
Dmitry Shmidt700a1372013-03-15 14:14:44 -0700166 wpa_s->parent->conf->p2p_ignore_shared_freq)
167 freq = 0;
168 p2p_set_own_freq_preference(wpa_s->global->p2p, freq);
169}
170
171
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700172static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
173 struct wpa_scan_results *scan_res)
174{
175 size_t i;
176
177 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
178 return;
179
180 wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS)",
181 (int) scan_res->num);
182
183 for (i = 0; i < scan_res->num; i++) {
184 struct wpa_scan_res *bss = scan_res->res[i];
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800185 struct os_time time_tmp_age, entry_ts;
186 time_tmp_age.sec = bss->age / 1000;
187 time_tmp_age.usec = (bss->age % 1000) * 1000;
188 os_time_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700189 if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800190 bss->freq, &entry_ts, bss->level,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700191 (const u8 *) (bss + 1),
192 bss->ie_len) > 0)
193 break;
194 }
195
196 p2p_scan_res_handled(wpa_s->global->p2p);
197}
198
199
200static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
201 unsigned int num_req_dev_types,
Dmitry Shmidt04949592012-07-19 12:16:46 -0700202 const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700203{
204 struct wpa_supplicant *wpa_s = ctx;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700205 struct wpa_supplicant *ifs;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700206 struct wpa_driver_scan_params params;
207 int ret;
208 struct wpabuf *wps_ie, *ies;
209 int social_channels[] = { 2412, 2437, 2462, 0, 0 };
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800210 size_t ielen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700211
212 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
213 return -1;
214
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700215 for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
216 if (ifs->sta_scan_pending &&
Dmitry Shmidt37d4d6a2013-03-18 13:09:42 -0700217 (wpas_scan_scheduled(ifs) || ifs->scanning) &&
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700218 wpas_p2p_in_progress(wpa_s) == 2) {
219 wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow "
220 "pending station mode scan to be "
221 "completed on interface %s", ifs->ifname);
Jouni Malinendc7b7132012-09-14 12:53:47 -0700222 wpa_s->global->p2p_cb_on_scan_complete = 1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700223 wpa_supplicant_req_scan(ifs, 0, 0);
224 return 1;
225 }
226 }
227
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700228 os_memset(&params, 0, sizeof(params));
229
230 /* P2P Wildcard SSID */
231 params.num_ssids = 1;
232 params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
233 params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
234
235 wpa_s->wps->dev.p2p = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700236 wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
237 wpa_s->wps->uuid, WPS_REQ_ENROLLEE,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700238 num_req_dev_types, req_dev_types);
239 if (wps_ie == NULL)
240 return -1;
241
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800242 ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
243 ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700244 if (ies == NULL) {
245 wpabuf_free(wps_ie);
246 return -1;
247 }
248 wpabuf_put_buf(ies, wps_ie);
249 wpabuf_free(wps_ie);
250
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800251 p2p_scan_ie(wpa_s->global->p2p, ies, dev_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700252
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800253 params.p2p_probe = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700254 params.extra_ies = wpabuf_head(ies);
255 params.extra_ies_len = wpabuf_len(ies);
256
257 switch (type) {
258 case P2P_SCAN_SOCIAL:
259 params.freqs = social_channels;
260 break;
261 case P2P_SCAN_FULL:
262 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700263 case P2P_SCAN_SOCIAL_PLUS_ONE:
264 social_channels[3] = freq;
265 params.freqs = social_channels;
266 break;
267 }
268
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800269 ret = wpa_drv_scan(wpa_s, &params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700270
271 wpabuf_free(ies);
272
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800273 if (ret) {
Jouni Malinen043a5a92012-09-13 18:03:14 -0700274 for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
275 if (ifs->scanning ||
276 ifs->scan_res_handler == wpas_p2p_scan_res_handler) {
277 wpa_s->global->p2p_cb_on_scan_complete = 1;
278 ret = 1;
279 break;
280 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800281 }
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700282 } else {
283 os_get_time(&wpa_s->scan_trigger_time);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700284 wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700285 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800286
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700287 return ret;
288}
289
290
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700291static enum wpa_driver_if_type wpas_p2p_if_type(int p2p_group_interface)
292{
293 switch (p2p_group_interface) {
294 case P2P_GROUP_INTERFACE_PENDING:
295 return WPA_IF_P2P_GROUP;
296 case P2P_GROUP_INTERFACE_GO:
297 return WPA_IF_P2P_GO;
298 case P2P_GROUP_INTERFACE_CLIENT:
299 return WPA_IF_P2P_CLIENT;
300 }
301
302 return WPA_IF_P2P_GROUP;
303}
304
305
306static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s,
307 const u8 *ssid,
308 size_t ssid_len, int *go)
309{
310 struct wpa_ssid *s;
311
312 for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
313 for (s = wpa_s->conf->ssid; s; s = s->next) {
314 if (s->disabled != 0 || !s->p2p_group ||
315 s->ssid_len != ssid_len ||
316 os_memcmp(ssid, s->ssid, ssid_len) != 0)
317 continue;
318 if (s->mode == WPAS_MODE_P2P_GO &&
319 s != wpa_s->current_ssid)
320 continue;
321 if (go)
322 *go = s->mode == WPAS_MODE_P2P_GO;
323 return wpa_s;
324 }
325 }
326
327 return NULL;
328}
329
330
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700331static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
332 enum p2p_group_removal_reason removal_reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700333{
334 struct wpa_ssid *ssid;
335 char *gtype;
336 const char *reason;
337
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700338 ssid = wpa_s->current_ssid;
339 if (ssid == NULL) {
340 /*
341 * The current SSID was not known, but there may still be a
Dmitry Shmidtaa532512012-09-24 10:35:31 -0700342 * pending P2P group interface waiting for provisioning or a
343 * P2P group that is trying to reconnect.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700344 */
345 ssid = wpa_s->conf->ssid;
346 while (ssid) {
Jouni Malinen9d712832012-10-05 11:01:57 -0700347 if (ssid->p2p_group && ssid->disabled != 2)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700348 break;
349 ssid = ssid->next;
350 }
Jouni Malinen5c44edb2012-08-31 21:35:32 +0300351 if (ssid == NULL &&
352 wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)
353 {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700354 wpa_printf(MSG_ERROR, "P2P: P2P group interface "
355 "not found");
356 return -1;
357 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700358 }
359 if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO)
360 gtype = "GO";
361 else if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT ||
362 (ssid && ssid->mode == WPAS_MODE_INFRA)) {
363 wpa_s->reassociate = 0;
364 wpa_s->disconnected = 1;
365 wpa_supplicant_deauthenticate(wpa_s,
366 WLAN_REASON_DEAUTH_LEAVING);
367 gtype = "client";
368 } else
369 gtype = "GO";
370 if (wpa_s->cross_connect_in_use) {
371 wpa_s->cross_connect_in_use = 0;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700372 wpa_msg_global(wpa_s->parent, MSG_INFO,
373 P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
374 wpa_s->ifname, wpa_s->cross_connect_uplink);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700375 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700376 switch (removal_reason) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700377 case P2P_GROUP_REMOVAL_REQUESTED:
378 reason = " reason=REQUESTED";
379 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700380 case P2P_GROUP_REMOVAL_FORMATION_FAILED:
381 reason = " reason=FORMATION_FAILED";
382 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700383 case P2P_GROUP_REMOVAL_IDLE_TIMEOUT:
384 reason = " reason=IDLE";
385 break;
386 case P2P_GROUP_REMOVAL_UNAVAILABLE:
387 reason = " reason=UNAVAILABLE";
388 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700389 case P2P_GROUP_REMOVAL_GO_ENDING_SESSION:
390 reason = " reason=GO_ENDING_SESSION";
391 break;
Dmitry Shmidt687922c2012-03-26 14:02:32 -0700392#ifdef ANDROID_P2P
393 case P2P_GROUP_REMOVAL_FREQ_CONFLICT:
394 reason = " reason=FREQ_CONFLICT";
395 break;
396#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700397 default:
398 reason = "";
399 break;
400 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700401 if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700402 wpa_msg_global(wpa_s->parent, MSG_INFO,
403 P2P_EVENT_GROUP_REMOVED "%s %s%s",
404 wpa_s->ifname, gtype, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700405 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700406
Dmitry Shmidt1cf45732013-04-29 17:36:45 -0700407#ifdef ANDROID_P2P
408 eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
409#endif
Dmitry Shmidt04949592012-07-19 12:16:46 -0700410 if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
411 wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800412 if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
Dmitry Shmidt2f023192013-03-12 12:44:17 -0700413 wpa_s->parent, NULL) > 0) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800414 wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation "
415 "timeout");
Dmitry Shmidt2f023192013-03-12 12:44:17 -0700416 wpa_s->p2p_in_provisioning = 0;
417 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700418
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700419 if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700420 wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
421
422 if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
423 struct wpa_global *global;
424 char *ifname;
425 enum wpa_driver_if_type type;
426 wpa_printf(MSG_DEBUG, "P2P: Remove group interface %s",
427 wpa_s->ifname);
428 global = wpa_s->global;
429 ifname = os_strdup(wpa_s->ifname);
430 type = wpas_p2p_if_type(wpa_s->p2p_group_interface);
Dmitry Shmidte15c7b52011-08-03 15:04:35 -0700431 wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700432 wpa_s = global->ifaces;
433 if (wpa_s && ifname)
434 wpa_drv_if_remove(wpa_s, type, ifname);
435 os_free(ifname);
Jouni Malinen2b89da82012-08-31 22:04:41 +0300436 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700437 }
438
439 wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
440 if (ssid && (ssid->p2p_group ||
441 ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
442 (ssid->key_mgmt & WPA_KEY_MGMT_WPS))) {
443 int id = ssid->id;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700444 if (ssid == wpa_s->current_ssid) {
445 wpa_sm_set_config(wpa_s->wpa, NULL);
446 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700447 wpa_s->current_ssid = NULL;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700448 }
449 /*
450 * Networks objects created during any P2P activities are not
451 * exposed out as they might/will confuse certain non-P2P aware
452 * applications since these network objects won't behave like
453 * regular ones.
454 *
455 * Likewise, we don't send out network removed signals for such
456 * network objects.
457 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700458 wpa_config_remove_network(wpa_s->conf, id);
459 wpa_supplicant_clear_status(wpa_s);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800460 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt91c40cd2012-09-25 14:23:53 -0700461 wpa_s->sta_scan_pending = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700462 } else {
463 wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
464 "found");
465 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700466 if (wpa_s->ap_iface)
467 wpa_supplicant_ap_deinit(wpa_s);
468 else
469 wpa_drv_deinit_p2p_cli(wpa_s);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700470
471 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700472}
473
474
475static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
476 u8 *go_dev_addr,
477 const u8 *ssid, size_t ssid_len)
478{
479 struct wpa_bss *bss;
480 const u8 *bssid;
481 struct wpabuf *p2p;
482 u8 group_capab;
483 const u8 *addr;
484
485 if (wpa_s->go_params)
486 bssid = wpa_s->go_params->peer_interface_addr;
487 else
488 bssid = wpa_s->bssid;
489
490 bss = wpa_bss_get(wpa_s, bssid, ssid, ssid_len);
491 if (bss == NULL) {
492 u8 iface_addr[ETH_ALEN];
493 if (p2p_get_interface_addr(wpa_s->global->p2p, bssid,
494 iface_addr) == 0)
495 bss = wpa_bss_get(wpa_s, iface_addr, ssid, ssid_len);
496 }
497 if (bss == NULL) {
498 wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether "
499 "group is persistent - BSS " MACSTR " not found",
500 MAC2STR(bssid));
501 return 0;
502 }
503
504 p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
505 if (p2p == NULL) {
506 wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether "
507 "group is persistent - BSS " MACSTR
508 " did not include P2P IE", MAC2STR(bssid));
509 wpa_hexdump(MSG_DEBUG, "P2P: Probe Response IEs",
510 (u8 *) (bss + 1), bss->ie_len);
511 wpa_hexdump(MSG_DEBUG, "P2P: Beacon IEs",
512 ((u8 *) bss + 1) + bss->ie_len,
513 bss->beacon_ie_len);
514 return 0;
515 }
516
517 group_capab = p2p_get_group_capab(p2p);
518 addr = p2p_get_go_dev_addr(p2p);
519 wpa_printf(MSG_DEBUG, "P2P: Checking whether group is persistent: "
520 "group_capab=0x%x", group_capab);
521 if (addr) {
522 os_memcpy(go_dev_addr, addr, ETH_ALEN);
523 wpa_printf(MSG_DEBUG, "P2P: GO Device Address " MACSTR,
524 MAC2STR(addr));
525 } else
526 os_memset(go_dev_addr, 0, ETH_ALEN);
527 wpabuf_free(p2p);
528
529 wpa_printf(MSG_DEBUG, "P2P: BSS " MACSTR " group_capab=0x%x "
530 "go_dev_addr=" MACSTR,
531 MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr));
532
533 return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP;
534}
535
536
Jouni Malinen75ecf522011-06-27 15:19:46 -0700537static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
538 struct wpa_ssid *ssid,
539 const u8 *go_dev_addr)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700540{
541 struct wpa_ssid *s;
542 int changed = 0;
543
544 wpa_printf(MSG_DEBUG, "P2P: Storing credentials for a persistent "
545 "group (GO Dev Addr " MACSTR ")", MAC2STR(go_dev_addr));
546 for (s = wpa_s->conf->ssid; s; s = s->next) {
547 if (s->disabled == 2 &&
548 os_memcmp(go_dev_addr, s->bssid, ETH_ALEN) == 0 &&
549 s->ssid_len == ssid->ssid_len &&
550 os_memcmp(ssid->ssid, s->ssid, ssid->ssid_len) == 0)
551 break;
552 }
553
554 if (s) {
555 wpa_printf(MSG_DEBUG, "P2P: Update existing persistent group "
556 "entry");
557 if (ssid->passphrase && !s->passphrase)
558 changed = 1;
559 else if (ssid->passphrase && s->passphrase &&
560 os_strcmp(ssid->passphrase, s->passphrase) != 0)
561 changed = 1;
562 } else {
563 wpa_printf(MSG_DEBUG, "P2P: Create a new persistent group "
564 "entry");
565 changed = 1;
566 s = wpa_config_add_network(wpa_s->conf);
567 if (s == NULL)
Jouni Malinen75ecf522011-06-27 15:19:46 -0700568 return -1;
569
570 /*
571 * Instead of network_added we emit persistent_group_added
572 * notification. Also to keep the defense checks in
573 * persistent_group obj registration method, we set the
574 * relevant flags in s to designate it as a persistent group.
575 */
576 s->p2p_group = 1;
577 s->p2p_persistent_group = 1;
578 wpas_notify_persistent_group_added(wpa_s, s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700579 wpa_config_set_network_defaults(s);
580 }
581
582 s->p2p_group = 1;
583 s->p2p_persistent_group = 1;
584 s->disabled = 2;
585 s->bssid_set = 1;
586 os_memcpy(s->bssid, go_dev_addr, ETH_ALEN);
587 s->mode = ssid->mode;
588 s->auth_alg = WPA_AUTH_ALG_OPEN;
589 s->key_mgmt = WPA_KEY_MGMT_PSK;
590 s->proto = WPA_PROTO_RSN;
591 s->pairwise_cipher = WPA_CIPHER_CCMP;
592 s->export_keys = 1;
593 if (ssid->passphrase) {
594 os_free(s->passphrase);
595 s->passphrase = os_strdup(ssid->passphrase);
596 }
597 if (ssid->psk_set) {
598 s->psk_set = 1;
599 os_memcpy(s->psk, ssid->psk, 32);
600 }
601 if (s->passphrase && !s->psk_set)
602 wpa_config_update_psk(s);
603 if (s->ssid == NULL || s->ssid_len < ssid->ssid_len) {
604 os_free(s->ssid);
605 s->ssid = os_malloc(ssid->ssid_len);
606 }
607 if (s->ssid) {
608 s->ssid_len = ssid->ssid_len;
609 os_memcpy(s->ssid, ssid->ssid, s->ssid_len);
610 }
611
612#ifndef CONFIG_NO_CONFIG_WRITE
613 if (changed && wpa_s->conf->update_config &&
614 wpa_config_write(wpa_s->confname, wpa_s->conf)) {
615 wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
616 }
617#endif /* CONFIG_NO_CONFIG_WRITE */
Jouni Malinen75ecf522011-06-27 15:19:46 -0700618
619 return s->id;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700620}
621
622
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800623static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
624 const u8 *addr)
625{
626 struct wpa_ssid *ssid, *s;
627 u8 *n;
628 size_t i;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700629 int found = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800630
631 ssid = wpa_s->current_ssid;
632 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
633 !ssid->p2p_persistent_group)
634 return;
635
636 for (s = wpa_s->parent->conf->ssid; s; s = s->next) {
637 if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO)
638 continue;
639
640 if (s->ssid_len == ssid->ssid_len &&
641 os_memcmp(s->ssid, ssid->ssid, s->ssid_len) == 0)
642 break;
643 }
644
645 if (s == NULL)
646 return;
647
648 for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
649 if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700650 ETH_ALEN) != 0)
651 continue;
652
653 if (i == s->num_p2p_clients - 1)
654 return; /* already the most recent entry */
655
656 /* move the entry to mark it most recent */
657 os_memmove(s->p2p_client_list + i * ETH_ALEN,
658 s->p2p_client_list + (i + 1) * ETH_ALEN,
659 (s->num_p2p_clients - i - 1) * ETH_ALEN);
660 os_memcpy(s->p2p_client_list +
661 (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN);
662 found = 1;
663 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800664 }
665
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700666 if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) {
667 n = os_realloc_array(s->p2p_client_list,
668 s->num_p2p_clients + 1, ETH_ALEN);
669 if (n == NULL)
670 return;
671 os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
672 s->p2p_client_list = n;
673 s->num_p2p_clients++;
674 } else if (!found) {
675 /* Not enough room for an additional entry - drop the oldest
676 * entry */
677 os_memmove(s->p2p_client_list,
678 s->p2p_client_list + ETH_ALEN,
679 (s->num_p2p_clients - 1) * ETH_ALEN);
680 os_memcpy(s->p2p_client_list +
681 (s->num_p2p_clients - 1) * ETH_ALEN,
682 addr, ETH_ALEN);
683 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800684
685#ifndef CONFIG_NO_CONFIG_WRITE
686 if (wpa_s->parent->conf->update_config &&
687 wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
688 wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
689#endif /* CONFIG_NO_CONFIG_WRITE */
690}
691
692
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700693static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
694 int success)
695{
696 struct wpa_ssid *ssid;
697 const char *ssid_txt;
698 int client;
699 int persistent;
700 u8 go_dev_addr[ETH_ALEN];
Jouni Malinen75ecf522011-06-27 15:19:46 -0700701 int network_id = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700702
703 /*
704 * This callback is likely called for the main interface. Update wpa_s
705 * to use the group interface if a new interface was created for the
706 * group.
707 */
708 if (wpa_s->global->p2p_group_formation)
709 wpa_s = wpa_s->global->p2p_group_formation;
710 wpa_s->global->p2p_group_formation = NULL;
711 wpa_s->p2p_in_provisioning = 0;
712
713 if (!success) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700714 wpa_msg_global(wpa_s->parent, MSG_INFO,
715 P2P_EVENT_GROUP_FORMATION_FAILURE);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700716 wpas_p2p_group_delete(wpa_s,
717 P2P_GROUP_REMOVAL_FORMATION_FAILED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700718 return;
719 }
720
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700721 wpa_msg_global(wpa_s->parent, MSG_INFO,
722 P2P_EVENT_GROUP_FORMATION_SUCCESS);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700723
724 ssid = wpa_s->current_ssid;
725 if (ssid && ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
726 ssid->mode = WPAS_MODE_P2P_GO;
727 p2p_group_notif_formation_done(wpa_s->p2p_group);
728 wpa_supplicant_ap_mac_addr_filter(wpa_s, NULL);
729 }
730
731 persistent = 0;
732 if (ssid) {
733 ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
734 client = ssid->mode == WPAS_MODE_INFRA;
735 if (ssid->mode == WPAS_MODE_P2P_GO) {
736 persistent = ssid->p2p_persistent_group;
Dmitry Shmidt497c1d52011-07-21 15:19:46 -0700737 os_memcpy(go_dev_addr, wpa_s->global->p2p_dev_addr,
738 ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700739 } else
740 persistent = wpas_p2p_persistent_group(wpa_s,
741 go_dev_addr,
742 ssid->ssid,
743 ssid->ssid_len);
744 } else {
745 ssid_txt = "";
746 client = wpa_s->p2p_group_interface ==
747 P2P_GROUP_INTERFACE_CLIENT;
748 os_memset(go_dev_addr, 0, ETH_ALEN);
749 }
750
751 wpa_s->show_group_started = 0;
752 if (client) {
753 /*
754 * Indicate event only after successfully completed 4-way
755 * handshake, i.e., when the interface is ready for data
756 * packets.
757 */
758 wpa_s->show_group_started = 1;
Dmitry Shmidt4b86ea52012-09-04 11:06:50 -0700759#ifdef ANDROID_P2P
760 /* For client Second phase of Group formation (4-way handshake) can be still pending
761 * So we need to restore wpa_s->global->p2p_group_formation */
Dmitry Shmidta2854ab2012-09-10 16:15:47 -0700762 wpa_printf(MSG_INFO, "Restoring back wpa_s->global->p2p_group_formation to wpa_s %p\n", wpa_s);
Dmitry Shmidt4b86ea52012-09-04 11:06:50 -0700763 wpa_s->global->p2p_group_formation = wpa_s;
764#endif
765
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700766 } else if (ssid && ssid->passphrase == NULL && ssid->psk_set) {
767 char psk[65];
768 wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700769 wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
770 "%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr="
771 MACSTR "%s",
772 wpa_s->ifname, ssid_txt, ssid->frequency, psk,
773 MAC2STR(go_dev_addr),
774 persistent ? " [PERSISTENT]" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700775 wpas_p2p_cross_connect_setup(wpa_s);
776 wpas_p2p_set_group_idle_timeout(wpa_s);
777 } else {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700778 wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
779 "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
780 "go_dev_addr=" MACSTR "%s",
781 wpa_s->ifname, ssid_txt,
782 ssid ? ssid->frequency : 0,
783 ssid && ssid->passphrase ? ssid->passphrase : "",
784 MAC2STR(go_dev_addr),
785 persistent ? " [PERSISTENT]" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700786 wpas_p2p_cross_connect_setup(wpa_s);
787 wpas_p2p_set_group_idle_timeout(wpa_s);
788 }
789
790 if (persistent)
Jouni Malinen75ecf522011-06-27 15:19:46 -0700791 network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
792 ssid, go_dev_addr);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800793 if (network_id < 0 && ssid)
Jouni Malinen75ecf522011-06-27 15:19:46 -0700794 network_id = ssid->id;
795 if (!client)
796 wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700797}
798
799
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800800static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
801 unsigned int freq,
802 const u8 *dst, const u8 *src,
803 const u8 *bssid,
804 const u8 *data, size_t data_len,
805 enum offchannel_send_action_result
806 result)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700807{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800808 enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700809
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700810 if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
811 return;
812 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
813 return;
814
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800815 switch (result) {
816 case OFFCHANNEL_SEND_ACTION_SUCCESS:
817 res = P2P_SEND_ACTION_SUCCESS;
818 break;
819 case OFFCHANNEL_SEND_ACTION_NO_ACK:
820 res = P2P_SEND_ACTION_NO_ACK;
821 break;
822 case OFFCHANNEL_SEND_ACTION_FAILED:
823 res = P2P_SEND_ACTION_FAILED;
824 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700825 }
826
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800827 p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700828
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800829 if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
830 wpa_s->pending_pd_before_join &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800831 (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800832 os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) &&
833 wpa_s->p2p_fallback_to_go_neg) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700834 wpa_s->pending_pd_before_join = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800835 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
836 "during p2p_connect-auto");
837 wpas_p2p_fallback_to_go_neg(wpa_s, 0);
838 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700839 }
840}
841
842
843static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
844 const u8 *src, const u8 *bssid, const u8 *buf,
845 size_t len, unsigned int wait_time)
846{
847 struct wpa_supplicant *wpa_s = ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800848 return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len,
849 wait_time,
850 wpas_p2p_send_action_tx_status, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700851}
852
853
854static void wpas_send_action_done(void *ctx)
855{
856 struct wpa_supplicant *wpa_s = ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800857 offchannel_send_action_done(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700858}
859
860
861static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
862 struct p2p_go_neg_results *params)
863{
864 if (wpa_s->go_params == NULL) {
865 wpa_s->go_params = os_malloc(sizeof(*params));
866 if (wpa_s->go_params == NULL)
867 return -1;
868 }
869 os_memcpy(wpa_s->go_params, params, sizeof(*params));
870 return 0;
871}
872
873
874static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
875 struct p2p_go_neg_results *res)
876{
877 wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR,
878 MAC2STR(res->peer_interface_addr));
879 wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID",
880 res->ssid, res->ssid_len);
881 wpa_supplicant_ap_deinit(wpa_s);
882 wpas_copy_go_neg_results(wpa_s, res);
883 if (res->wps_method == WPS_PBC)
884 wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
885 else {
886 u16 dev_pw_id = DEV_PW_DEFAULT;
887 if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
888 dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
889 wpas_wps_start_pin(wpa_s, res->peer_interface_addr,
890 wpa_s->p2p_pin, 1, dev_pw_id);
891 }
892}
893
894
895static void p2p_go_configured(void *ctx, void *data)
896{
897 struct wpa_supplicant *wpa_s = ctx;
898 struct p2p_go_neg_results *params = data;
899 struct wpa_ssid *ssid;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700900 int network_id = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700901
902 ssid = wpa_s->current_ssid;
903 if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
904 wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
905 if (wpa_s->global->p2p_group_formation == wpa_s)
906 wpa_s->global->p2p_group_formation = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800907 if (os_strlen(params->passphrase) > 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700908 wpa_msg_global(wpa_s->parent, MSG_INFO,
909 P2P_EVENT_GROUP_STARTED
910 "%s GO ssid=\"%s\" freq=%d "
911 "passphrase=\"%s\" go_dev_addr=" MACSTR
912 "%s", wpa_s->ifname,
913 wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
914 ssid->frequency, params->passphrase,
915 MAC2STR(wpa_s->global->p2p_dev_addr),
916 params->persistent_group ?
917 " [PERSISTENT]" : "");
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800918 } else {
919 char psk[65];
920 wpa_snprintf_hex(psk, sizeof(psk), params->psk,
921 sizeof(params->psk));
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700922 wpa_msg_global(wpa_s->parent, MSG_INFO,
923 P2P_EVENT_GROUP_STARTED
924 "%s GO ssid=\"%s\" freq=%d psk=%s "
925 "go_dev_addr=" MACSTR "%s",
926 wpa_s->ifname,
927 wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
928 ssid->frequency, psk,
929 MAC2STR(wpa_s->global->p2p_dev_addr),
930 params->persistent_group ?
931 " [PERSISTENT]" : "");
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800932 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800933
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700934 if (params->persistent_group)
Jouni Malinen75ecf522011-06-27 15:19:46 -0700935 network_id = wpas_p2p_store_persistent_group(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700936 wpa_s->parent, ssid,
Dmitry Shmidt497c1d52011-07-21 15:19:46 -0700937 wpa_s->global->p2p_dev_addr);
Jouni Malinen75ecf522011-06-27 15:19:46 -0700938 if (network_id < 0)
939 network_id = ssid->id;
940 wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700941 wpas_p2p_cross_connect_setup(wpa_s);
942 wpas_p2p_set_group_idle_timeout(wpa_s);
943 return;
944 }
945
946 wpa_printf(MSG_DEBUG, "P2P: Setting up WPS for GO provisioning");
947 if (wpa_supplicant_ap_mac_addr_filter(wpa_s,
948 params->peer_interface_addr)) {
949 wpa_printf(MSG_DEBUG, "P2P: Failed to setup MAC address "
950 "filtering");
951 return;
952 }
953 if (params->wps_method == WPS_PBC)
954 wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800955 params->peer_device_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700956 else if (wpa_s->p2p_pin[0])
957 wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800958 wpa_s->p2p_pin, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700959 os_free(wpa_s->go_params);
960 wpa_s->go_params = NULL;
961}
962
963
964static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
965 struct p2p_go_neg_results *params,
966 int group_formation)
967{
968 struct wpa_ssid *ssid;
969
Dmitry Shmidtaa532512012-09-24 10:35:31 -0700970 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Starting GO");
971 if (wpas_copy_go_neg_results(wpa_s, params) < 0) {
972 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not copy GO Negotiation "
973 "results");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700974 return;
Dmitry Shmidtaa532512012-09-24 10:35:31 -0700975 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700976
977 ssid = wpa_config_add_network(wpa_s->conf);
Dmitry Shmidtaa532512012-09-24 10:35:31 -0700978 if (ssid == NULL) {
979 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not add network for GO");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700980 return;
Dmitry Shmidtaa532512012-09-24 10:35:31 -0700981 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700982
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800983 wpa_s->show_group_started = 0;
984
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700985 wpa_config_set_network_defaults(ssid);
986 ssid->temporary = 1;
987 ssid->p2p_group = 1;
988 ssid->p2p_persistent_group = params->persistent_group;
989 ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
990 WPAS_MODE_P2P_GO;
991 ssid->frequency = params->freq;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700992 ssid->ht40 = params->ht40;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700993 ssid->ssid = os_zalloc(params->ssid_len + 1);
994 if (ssid->ssid) {
995 os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
996 ssid->ssid_len = params->ssid_len;
997 }
998 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
999 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
1000 ssid->proto = WPA_PROTO_RSN;
1001 ssid->pairwise_cipher = WPA_CIPHER_CCMP;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001002 if (os_strlen(params->passphrase) > 0) {
1003 ssid->passphrase = os_strdup(params->passphrase);
1004 if (ssid->passphrase == NULL) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001005 wpa_msg_global(wpa_s, MSG_ERROR,
1006 "P2P: Failed to copy passphrase for GO");
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001007 wpa_config_remove_network(wpa_s->conf, ssid->id);
1008 return;
1009 }
1010 } else
1011 ssid->passphrase = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001012 ssid->psk_set = params->psk_set;
1013 if (ssid->psk_set)
1014 os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001015 else if (ssid->passphrase)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001016 wpa_config_update_psk(ssid);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001017 ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001018
1019 wpa_s->ap_configured_cb = p2p_go_configured;
1020 wpa_s->ap_configured_cb_ctx = wpa_s;
1021 wpa_s->ap_configured_cb_data = wpa_s->go_params;
Jouni Malinen75ecf522011-06-27 15:19:46 -07001022 wpa_s->connect_without_scan = ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001023 wpa_s->reassociate = 1;
1024 wpa_s->disconnected = 0;
Dmitry Shmidtaa532512012-09-24 10:35:31 -07001025 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Request scan (that will be skipped) to "
1026 "start GO)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001027 wpa_supplicant_req_scan(wpa_s, 0, 0);
1028}
1029
1030
1031static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
1032 const struct wpa_supplicant *src)
1033{
1034 struct wpa_config *d;
1035 const struct wpa_config *s;
1036
1037 d = dst->conf;
1038 s = src->conf;
1039
1040#define C(n) if (s->n) d->n = os_strdup(s->n)
1041 C(device_name);
1042 C(manufacturer);
1043 C(model_name);
1044 C(model_number);
1045 C(serial_number);
1046 C(config_methods);
1047#undef C
1048
1049 os_memcpy(d->device_type, s->device_type, WPS_DEV_TYPE_LEN);
1050 os_memcpy(d->sec_device_type, s->sec_device_type,
1051 sizeof(d->sec_device_type));
1052 d->num_sec_device_types = s->num_sec_device_types;
1053
1054 d->p2p_group_idle = s->p2p_group_idle;
1055 d->p2p_intra_bss = s->p2p_intra_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001056 d->persistent_reconnect = s->persistent_reconnect;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001057 d->max_num_sta = s->max_num_sta;
1058 d->pbc_in_m1 = s->pbc_in_m1;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07001059 d->ignore_old_scan_res = s->ignore_old_scan_res;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07001060 d->beacon_int = s->beacon_int;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001061 d->disassoc_low_ack = s->disassoc_low_ack;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001062}
1063
1064
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001065static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s,
1066 char *ifname, size_t len)
1067{
1068 char *ifname_ptr = wpa_s->ifname;
1069
1070 if (os_strncmp(wpa_s->ifname, P2P_MGMT_DEVICE_PREFIX,
1071 os_strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
1072 ifname_ptr = os_strrchr(wpa_s->ifname, '-') + 1;
1073 }
1074
1075 os_snprintf(ifname, len, "p2p-%s-%d", ifname_ptr, wpa_s->p2p_group_idx);
1076 if (os_strlen(ifname) >= IFNAMSIZ &&
1077 os_strlen(wpa_s->ifname) < IFNAMSIZ) {
1078 /* Try to avoid going over the IFNAMSIZ length limit */
1079 os_snprintf(ifname, sizeof(ifname), "p2p-%d",
1080 wpa_s->p2p_group_idx);
1081 }
1082}
1083
1084
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001085static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
1086 enum wpa_driver_if_type type)
1087{
1088 char ifname[120], force_ifname[120];
1089
1090 if (wpa_s->pending_interface_name[0]) {
1091 wpa_printf(MSG_DEBUG, "P2P: Pending virtual interface exists "
1092 "- skip creation of a new one");
1093 if (is_zero_ether_addr(wpa_s->pending_interface_addr)) {
1094 wpa_printf(MSG_DEBUG, "P2P: Pending virtual address "
1095 "unknown?! ifname='%s'",
1096 wpa_s->pending_interface_name);
1097 return -1;
1098 }
1099 return 0;
1100 }
1101
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001102 wpas_p2p_get_group_ifname(wpa_s, ifname, sizeof(ifname));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001103 force_ifname[0] = '\0';
1104
1105 wpa_printf(MSG_DEBUG, "P2P: Create a new interface %s for the group",
1106 ifname);
1107 wpa_s->p2p_group_idx++;
1108
1109 wpa_s->pending_interface_type = type;
1110 if (wpa_drv_if_add(wpa_s, type, ifname, NULL, NULL, force_ifname,
1111 wpa_s->pending_interface_addr, NULL) < 0) {
1112 wpa_printf(MSG_ERROR, "P2P: Failed to create new group "
1113 "interface");
1114 return -1;
1115 }
1116
1117 if (force_ifname[0]) {
1118 wpa_printf(MSG_DEBUG, "P2P: Driver forced interface name %s",
1119 force_ifname);
1120 os_strlcpy(wpa_s->pending_interface_name, force_ifname,
1121 sizeof(wpa_s->pending_interface_name));
1122 } else
1123 os_strlcpy(wpa_s->pending_interface_name, ifname,
1124 sizeof(wpa_s->pending_interface_name));
1125 wpa_printf(MSG_DEBUG, "P2P: Created pending virtual interface %s addr "
1126 MACSTR, wpa_s->pending_interface_name,
1127 MAC2STR(wpa_s->pending_interface_addr));
1128
1129 return 0;
1130}
1131
1132
1133static void wpas_p2p_remove_pending_group_interface(
1134 struct wpa_supplicant *wpa_s)
1135{
1136 if (!wpa_s->pending_interface_name[0] ||
1137 is_zero_ether_addr(wpa_s->pending_interface_addr))
1138 return; /* No pending virtual interface */
1139
1140 wpa_printf(MSG_DEBUG, "P2P: Removing pending group interface %s",
1141 wpa_s->pending_interface_name);
1142 wpa_drv_if_remove(wpa_s, wpa_s->pending_interface_type,
1143 wpa_s->pending_interface_name);
1144 os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
1145 wpa_s->pending_interface_name[0] = '\0';
1146}
1147
1148
1149static struct wpa_supplicant *
1150wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go)
1151{
1152 struct wpa_interface iface;
1153 struct wpa_supplicant *group_wpa_s;
1154
1155 if (!wpa_s->pending_interface_name[0]) {
1156 wpa_printf(MSG_ERROR, "P2P: No pending group interface");
1157 if (!wpas_p2p_create_iface(wpa_s))
1158 return NULL;
1159 /*
1160 * Something has forced us to remove the pending interface; try
1161 * to create a new one and hope for the best that we will get
1162 * the same local address.
1163 */
1164 if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
1165 WPA_IF_P2P_CLIENT) < 0)
1166 return NULL;
1167 }
1168
1169 os_memset(&iface, 0, sizeof(iface));
1170 iface.ifname = wpa_s->pending_interface_name;
1171 iface.driver = wpa_s->driver->name;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001172 if (wpa_s->conf->ctrl_interface == NULL &&
1173 wpa_s->parent != wpa_s &&
1174 wpa_s->p2p_mgmt &&
1175 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE))
1176 iface.ctrl_interface = wpa_s->parent->conf->ctrl_interface;
1177 else
1178 iface.ctrl_interface = wpa_s->conf->ctrl_interface;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001179 iface.driver_param = wpa_s->conf->driver_param;
1180 group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
1181 if (group_wpa_s == NULL) {
1182 wpa_printf(MSG_ERROR, "P2P: Failed to create new "
1183 "wpa_supplicant interface");
1184 return NULL;
1185 }
1186 wpa_s->pending_interface_name[0] = '\0';
1187 group_wpa_s->parent = wpa_s;
1188 group_wpa_s->p2p_group_interface = go ? P2P_GROUP_INTERFACE_GO :
1189 P2P_GROUP_INTERFACE_CLIENT;
1190 wpa_s->global->p2p_group_formation = group_wpa_s;
1191
1192 wpas_p2p_clone_config(group_wpa_s, wpa_s);
1193
1194 return group_wpa_s;
1195}
1196
1197
1198static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
1199 void *timeout_ctx)
1200{
1201 struct wpa_supplicant *wpa_s = eloop_ctx;
1202 wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001203 wpas_p2p_group_formation_failed(wpa_s);
1204}
1205
1206
1207void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
1208{
1209 eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
1210 wpa_s->parent, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001211 if (wpa_s->global->p2p)
1212 p2p_group_formation_failed(wpa_s->global->p2p);
1213 else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
1214 wpa_drv_p2p_group_formation_failed(wpa_s);
1215 wpas_group_formation_completed(wpa_s, 0);
1216}
1217
1218
1219void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
1220{
1221 struct wpa_supplicant *wpa_s = ctx;
1222
1223 if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
1224 wpa_drv_cancel_remain_on_channel(wpa_s);
1225 wpa_s->off_channel_freq = 0;
1226 wpa_s->roc_waiting_drv_freq = 0;
1227 }
1228
1229 if (res->status) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001230 wpa_msg_global(wpa_s, MSG_INFO,
1231 P2P_EVENT_GO_NEG_FAILURE "status=%d",
1232 res->status);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001233 wpas_notify_p2p_go_neg_completed(wpa_s, res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001234 wpas_p2p_remove_pending_group_interface(wpa_s);
1235 return;
1236 }
1237
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001238 if (wpa_s->p2p_go_ht40)
1239 res->ht40 = 1;
1240
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001241 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
1242 "freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
1243 " wps_method=%s",
1244 res->role_go ? "GO" : "client", res->freq, res->ht40,
1245 MAC2STR(res->peer_device_addr),
1246 MAC2STR(res->peer_interface_addr),
1247 p2p_wps_method_text(res->wps_method));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001248 wpas_notify_p2p_go_neg_completed(wpa_s, res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001249
Dmitry Shmidt04949592012-07-19 12:16:46 -07001250 if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
1251 struct wpa_ssid *ssid;
1252 ssid = wpa_config_get_network(wpa_s->conf,
1253 wpa_s->p2p_persistent_id);
1254 if (ssid && ssid->disabled == 2 &&
1255 ssid->mode == WPAS_MODE_P2P_GO && ssid->passphrase) {
1256 size_t len = os_strlen(ssid->passphrase);
1257 wpa_printf(MSG_DEBUG, "P2P: Override passphrase based "
1258 "on requested persistent group");
1259 os_memcpy(res->passphrase, ssid->passphrase, len);
1260 res->passphrase[len] = '\0';
1261 }
1262 }
1263
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001264 if (wpa_s->create_p2p_iface) {
1265 struct wpa_supplicant *group_wpa_s =
1266 wpas_p2p_init_group_interface(wpa_s, res->role_go);
1267 if (group_wpa_s == NULL) {
1268 wpas_p2p_remove_pending_group_interface(wpa_s);
1269 return;
1270 }
1271 if (group_wpa_s != wpa_s) {
1272 os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
1273 sizeof(group_wpa_s->p2p_pin));
1274 group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
1275 }
1276 os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
1277 wpa_s->pending_interface_name[0] = '\0';
1278 group_wpa_s->p2p_in_provisioning = 1;
1279
1280 if (res->role_go)
1281 wpas_start_wps_go(group_wpa_s, res, 1);
1282 else
1283 wpas_start_wps_enrollee(group_wpa_s, res);
1284 } else {
1285 wpa_s->p2p_in_provisioning = 1;
1286 wpa_s->global->p2p_group_formation = wpa_s;
1287
1288 if (res->role_go)
1289 wpas_start_wps_go(wpa_s, res, 1);
1290 else
1291 wpas_start_wps_enrollee(ctx, res);
1292 }
1293
1294 wpa_s->p2p_long_listen = 0;
1295 eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
1296
1297 eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
1298 eloop_register_timeout(15 + res->peer_config_timeout / 100,
1299 (res->peer_config_timeout % 100) * 10000,
1300 wpas_p2p_group_formation_timeout, wpa_s, NULL);
1301}
1302
1303
1304void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
1305{
1306 struct wpa_supplicant *wpa_s = ctx;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001307 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
1308 " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001309
1310 wpas_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
1311}
1312
1313
1314void wpas_dev_found(void *ctx, const u8 *addr,
1315 const struct p2p_peer_info *info,
1316 int new_device)
1317{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001318#ifndef CONFIG_NO_STDOUT_DEBUG
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001319 struct wpa_supplicant *wpa_s = ctx;
1320 char devtype[WPS_DEV_TYPE_BUFSIZE];
Irfan Sheriff8367dc92012-09-09 17:08:19 -07001321#define WFD_DEV_INFO_SIZE 9
1322 char wfd_dev_info_hex[2 * WFD_DEV_INFO_SIZE + 1];
Irfan Sheriff8d965182012-09-11 08:58:24 -07001323 os_memset(wfd_dev_info_hex, 0, sizeof(wfd_dev_info_hex));
Irfan Sheriff8367dc92012-09-09 17:08:19 -07001324#ifdef CONFIG_WIFI_DISPLAY
1325 if (info->wfd_subelems) {
1326 wpa_snprintf_hex(wfd_dev_info_hex, sizeof(wfd_dev_info_hex),
1327 wpabuf_head(info->wfd_subelems),
1328 WFD_DEV_INFO_SIZE);
1329 }
1330#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001331 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
1332 " p2p_dev_addr=" MACSTR
1333 " pri_dev_type=%s name='%s' config_methods=0x%x "
1334 "dev_capab=0x%x group_capab=0x%x%s%s",
1335 MAC2STR(addr), MAC2STR(info->p2p_device_addr),
1336 wps_dev_type_bin2str(info->pri_dev_type, devtype,
1337 sizeof(devtype)),
1338 info->device_name, info->config_methods,
1339 info->dev_capab, info->group_capab,
1340 wfd_dev_info_hex[0] ? " wfd_dev_info=0x" : "", wfd_dev_info_hex);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001341#endif /* CONFIG_NO_STDOUT_DEBUG */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001342
1343 wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
1344}
1345
1346
1347static void wpas_dev_lost(void *ctx, const u8 *dev_addr)
1348{
1349 struct wpa_supplicant *wpa_s = ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001350
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001351 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
1352 "p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001353
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001354 wpas_notify_p2p_device_lost(wpa_s, dev_addr);
1355}
1356
1357
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001358static void wpas_find_stopped(void *ctx)
1359{
1360 struct wpa_supplicant *wpa_s = ctx;
1361 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED);
1362}
1363
1364
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001365static int wpas_start_listen(void *ctx, unsigned int freq,
1366 unsigned int duration,
1367 const struct wpabuf *probe_resp_ie)
1368{
1369 struct wpa_supplicant *wpa_s = ctx;
1370
1371 wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL);
1372
1373 if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
1374 wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
1375 "report received Probe Request frames");
1376 return -1;
1377 }
1378
1379 wpa_s->pending_listen_freq = freq;
1380 wpa_s->pending_listen_duration = duration;
1381
1382 if (wpa_drv_remain_on_channel(wpa_s, freq, duration) < 0) {
1383 wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
1384 "to remain on channel (%u MHz) for Listen "
1385 "state", freq);
1386 wpa_s->pending_listen_freq = 0;
1387 return -1;
1388 }
1389 wpa_s->off_channel_freq = 0;
1390 wpa_s->roc_waiting_drv_freq = freq;
1391
1392 return 0;
1393}
1394
1395
1396static void wpas_stop_listen(void *ctx)
1397{
1398 struct wpa_supplicant *wpa_s = ctx;
1399 if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
1400 wpa_drv_cancel_remain_on_channel(wpa_s);
1401 wpa_s->off_channel_freq = 0;
1402 wpa_s->roc_waiting_drv_freq = 0;
1403 }
1404 wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
1405 wpa_drv_probe_req_report(wpa_s, 0);
1406}
1407
1408
1409static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
1410{
1411 struct wpa_supplicant *wpa_s = ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001412 return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001413}
1414
1415
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001416/*
1417 * DNS Header section is used only to calculate compression pointers, so the
1418 * contents of this data does not matter, but the length needs to be reserved
1419 * in the virtual packet.
1420 */
1421#define DNS_HEADER_LEN 12
1422
1423/*
1424 * 27-octet in-memory packet from P2P specification containing two implied
1425 * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
1426 */
1427#define P2P_SD_IN_MEMORY_LEN 27
1428
1429static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
1430 u8 **spos, const u8 *end)
1431{
1432 while (*spos < end) {
1433 u8 val = ((*spos)[0] & 0xc0) >> 6;
1434 int len;
1435
1436 if (val == 1 || val == 2) {
1437 /* These are reserved values in RFC 1035 */
1438 wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
1439 "sequence starting with 0x%x", val);
1440 return -1;
1441 }
1442
1443 if (val == 3) {
1444 u16 offset;
1445 u8 *spos_tmp;
1446
1447 /* Offset */
1448 if (*spos + 2 > end) {
1449 wpa_printf(MSG_DEBUG, "P2P: No room for full "
1450 "DNS offset field");
1451 return -1;
1452 }
1453
1454 offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
1455 if (offset >= *spos - start) {
1456 wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
1457 "pointer offset %u", offset);
1458 return -1;
1459 }
1460
1461 (*spos) += 2;
1462 spos_tmp = start + offset;
1463 return p2p_sd_dns_uncompress_label(upos, uend, start,
1464 &spos_tmp,
1465 *spos - 2);
1466 }
1467
1468 /* Label */
1469 len = (*spos)[0] & 0x3f;
1470 if (len == 0)
1471 return 0;
1472
1473 (*spos)++;
1474 if (*spos + len > end) {
1475 wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
1476 "sequence - no room for label with length "
1477 "%u", len);
1478 return -1;
1479 }
1480
1481 if (*upos + len + 2 > uend)
1482 return -2;
1483
1484 os_memcpy(*upos, *spos, len);
1485 *spos += len;
1486 *upos += len;
1487 (*upos)[0] = '.';
1488 (*upos)++;
1489 (*upos)[0] = '\0';
1490 }
1491
1492 return 0;
1493}
1494
1495
1496/* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
1497 * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
1498 * not large enough */
1499static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
1500 size_t msg_len, size_t offset)
1501{
1502 /* 27-octet in-memory packet from P2P specification */
1503 const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
1504 "\x04_udp\xC0\x11\x00\x0C\x00\x01";
1505 u8 *tmp, *end, *spos;
1506 char *upos, *uend;
1507 int ret = 0;
1508
1509 if (buf_len < 2)
1510 return -1;
1511 if (offset > msg_len)
1512 return -1;
1513
1514 tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
1515 if (tmp == NULL)
1516 return -1;
1517 spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
1518 end = spos + msg_len;
1519 spos += offset;
1520
1521 os_memset(tmp, 0, DNS_HEADER_LEN);
1522 os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
1523 os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
1524
1525 upos = buf;
1526 uend = buf + buf_len;
1527
1528 ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
1529 if (ret) {
1530 os_free(tmp);
1531 return ret;
1532 }
1533
1534 if (upos == buf) {
1535 upos[0] = '.';
1536 upos[1] = '\0';
1537 } else if (upos[-1] == '.')
1538 upos[-1] = '\0';
1539
1540 os_free(tmp);
1541 return 0;
1542}
1543
1544
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001545static struct p2p_srv_bonjour *
1546wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
1547 const struct wpabuf *query)
1548{
1549 struct p2p_srv_bonjour *bsrv;
1550 size_t len;
1551
1552 len = wpabuf_len(query);
1553 dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
1554 struct p2p_srv_bonjour, list) {
1555 if (len == wpabuf_len(bsrv->query) &&
1556 os_memcmp(wpabuf_head(query), wpabuf_head(bsrv->query),
1557 len) == 0)
1558 return bsrv;
1559 }
1560 return NULL;
1561}
1562
1563
1564static struct p2p_srv_upnp *
1565wpas_p2p_service_get_upnp(struct wpa_supplicant *wpa_s, u8 version,
1566 const char *service)
1567{
1568 struct p2p_srv_upnp *usrv;
1569
1570 dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
1571 struct p2p_srv_upnp, list) {
1572 if (version == usrv->version &&
1573 os_strcmp(service, usrv->service) == 0)
1574 return usrv;
1575 }
1576 return NULL;
1577}
1578
1579
1580static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
1581 u8 srv_trans_id)
1582{
1583 u8 *len_pos;
1584
1585 if (wpabuf_tailroom(resp) < 5)
1586 return;
1587
1588 /* Length (to be filled) */
1589 len_pos = wpabuf_put(resp, 2);
1590 wpabuf_put_u8(resp, srv_proto);
1591 wpabuf_put_u8(resp, srv_trans_id);
1592 /* Status Code */
1593 wpabuf_put_u8(resp, P2P_SD_PROTO_NOT_AVAILABLE);
1594 /* Response Data: empty */
1595 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
1596}
1597
1598
1599static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
1600 struct wpabuf *resp, u8 srv_trans_id)
1601{
1602 struct p2p_srv_bonjour *bsrv;
1603 u8 *len_pos;
1604
1605 wpa_printf(MSG_DEBUG, "P2P: SD Request for all Bonjour services");
1606
1607 if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
1608 wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
1609 return;
1610 }
1611
1612 dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
1613 struct p2p_srv_bonjour, list) {
1614 if (wpabuf_tailroom(resp) <
1615 5 + wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp))
1616 return;
1617 /* Length (to be filled) */
1618 len_pos = wpabuf_put(resp, 2);
1619 wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
1620 wpabuf_put_u8(resp, srv_trans_id);
1621 /* Status Code */
1622 wpabuf_put_u8(resp, P2P_SD_SUCCESS);
1623 wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
1624 wpabuf_head(bsrv->resp),
1625 wpabuf_len(bsrv->resp));
1626 /* Response Data */
1627 wpabuf_put_buf(resp, bsrv->query); /* Key */
1628 wpabuf_put_buf(resp, bsrv->resp); /* Value */
1629 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
1630 2);
1631 }
1632}
1633
1634
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001635static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
1636 size_t query_len)
1637{
1638 char str_rx[256], str_srv[256];
1639
1640 if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
1641 return 0; /* Too short to include DNS Type and Version */
1642 if (os_memcmp(query + query_len - 3,
1643 wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
1644 3) != 0)
1645 return 0; /* Mismatch in DNS Type or Version */
1646 if (query_len == wpabuf_len(bsrv->query) &&
1647 os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
1648 return 1; /* Binary match */
1649
1650 if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
1651 0))
1652 return 0; /* Failed to uncompress query */
1653 if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
1654 wpabuf_head(bsrv->query),
1655 wpabuf_len(bsrv->query) - 3, 0))
1656 return 0; /* Failed to uncompress service */
1657
1658 return os_strcmp(str_rx, str_srv) == 0;
1659}
1660
1661
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001662static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
1663 struct wpabuf *resp, u8 srv_trans_id,
1664 const u8 *query, size_t query_len)
1665{
1666 struct p2p_srv_bonjour *bsrv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001667 u8 *len_pos;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001668 int matches = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001669
1670 wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
1671 query, query_len);
1672 if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
1673 wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
1674 wpas_sd_add_proto_not_avail(resp, P2P_SERV_BONJOUR,
1675 srv_trans_id);
1676 return;
1677 }
1678
1679 if (query_len == 0) {
1680 wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
1681 return;
1682 }
1683
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001684 dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
1685 struct p2p_srv_bonjour, list) {
1686 if (!match_bonjour_query(bsrv, query, query_len))
1687 continue;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001688
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001689 if (wpabuf_tailroom(resp) <
1690 5 + query_len + wpabuf_len(bsrv->resp))
1691 return;
1692
1693 matches++;
1694
1695 /* Length (to be filled) */
1696 len_pos = wpabuf_put(resp, 2);
1697 wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
1698 wpabuf_put_u8(resp, srv_trans_id);
1699
1700 /* Status Code */
1701 wpabuf_put_u8(resp, P2P_SD_SUCCESS);
1702 wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
1703 wpabuf_head(bsrv->resp),
1704 wpabuf_len(bsrv->resp));
1705
1706 /* Response Data */
1707 wpabuf_put_data(resp, query, query_len); /* Key */
1708 wpabuf_put_buf(resp, bsrv->resp); /* Value */
1709
1710 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
1711 }
1712
1713 if (matches == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001714 wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
1715 "available");
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001716 if (wpabuf_tailroom(resp) < 5)
1717 return;
1718
1719 /* Length (to be filled) */
1720 len_pos = wpabuf_put(resp, 2);
1721 wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
1722 wpabuf_put_u8(resp, srv_trans_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001723
1724 /* Status Code */
1725 wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
1726 /* Response Data: empty */
1727 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
1728 2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001729 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001730}
1731
1732
1733static void wpas_sd_all_upnp(struct wpa_supplicant *wpa_s,
1734 struct wpabuf *resp, u8 srv_trans_id)
1735{
1736 struct p2p_srv_upnp *usrv;
1737 u8 *len_pos;
1738
1739 wpa_printf(MSG_DEBUG, "P2P: SD Request for all UPnP services");
1740
1741 if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
1742 wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
1743 return;
1744 }
1745
1746 dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
1747 struct p2p_srv_upnp, list) {
1748 if (wpabuf_tailroom(resp) < 5 + 1 + os_strlen(usrv->service))
1749 return;
1750
1751 /* Length (to be filled) */
1752 len_pos = wpabuf_put(resp, 2);
1753 wpabuf_put_u8(resp, P2P_SERV_UPNP);
1754 wpabuf_put_u8(resp, srv_trans_id);
1755
1756 /* Status Code */
1757 wpabuf_put_u8(resp, P2P_SD_SUCCESS);
1758 /* Response Data */
1759 wpabuf_put_u8(resp, usrv->version);
1760 wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
1761 usrv->service);
1762 wpabuf_put_str(resp, usrv->service);
1763 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
1764 2);
1765 }
1766}
1767
1768
1769static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s,
1770 struct wpabuf *resp, u8 srv_trans_id,
1771 const u8 *query, size_t query_len)
1772{
1773 struct p2p_srv_upnp *usrv;
1774 u8 *len_pos;
1775 u8 version;
1776 char *str;
1777 int count = 0;
1778
1779 wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for UPnP",
1780 query, query_len);
1781
1782 if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
1783 wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
1784 wpas_sd_add_proto_not_avail(resp, P2P_SERV_UPNP,
1785 srv_trans_id);
1786 return;
1787 }
1788
1789 if (query_len == 0) {
1790 wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
1791 return;
1792 }
1793
1794 if (wpabuf_tailroom(resp) < 5)
1795 return;
1796
1797 /* Length (to be filled) */
1798 len_pos = wpabuf_put(resp, 2);
1799 wpabuf_put_u8(resp, P2P_SERV_UPNP);
1800 wpabuf_put_u8(resp, srv_trans_id);
1801
1802 version = query[0];
1803 str = os_malloc(query_len);
1804 if (str == NULL)
1805 return;
1806 os_memcpy(str, query + 1, query_len - 1);
1807 str[query_len - 1] = '\0';
1808
1809 dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
1810 struct p2p_srv_upnp, list) {
1811 if (version != usrv->version)
1812 continue;
1813
1814 if (os_strcmp(str, "ssdp:all") != 0 &&
1815 os_strstr(usrv->service, str) == NULL)
1816 continue;
1817
1818 if (wpabuf_tailroom(resp) < 2)
1819 break;
1820 if (count == 0) {
1821 /* Status Code */
1822 wpabuf_put_u8(resp, P2P_SD_SUCCESS);
1823 /* Response Data */
1824 wpabuf_put_u8(resp, version);
1825 } else
1826 wpabuf_put_u8(resp, ',');
1827
1828 count++;
1829
1830 wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
1831 usrv->service);
1832 if (wpabuf_tailroom(resp) < os_strlen(usrv->service))
1833 break;
1834 wpabuf_put_str(resp, usrv->service);
1835 }
1836 os_free(str);
1837
1838 if (count == 0) {
1839 wpa_printf(MSG_DEBUG, "P2P: Requested UPnP service not "
1840 "available");
1841 /* Status Code */
1842 wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
1843 /* Response Data: empty */
1844 }
1845
1846 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
1847}
1848
1849
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001850#ifdef CONFIG_WIFI_DISPLAY
1851static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s,
1852 struct wpabuf *resp, u8 srv_trans_id,
1853 const u8 *query, size_t query_len)
1854{
1855 const u8 *pos;
1856 u8 role;
1857 u8 *len_pos;
1858
1859 wpa_hexdump(MSG_DEBUG, "P2P: SD Request for WFD", query, query_len);
1860
1861 if (!wpa_s->global->wifi_display) {
1862 wpa_printf(MSG_DEBUG, "P2P: WFD protocol not available");
1863 wpas_sd_add_proto_not_avail(resp, P2P_SERV_WIFI_DISPLAY,
1864 srv_trans_id);
1865 return;
1866 }
1867
1868 if (query_len < 1) {
1869 wpa_printf(MSG_DEBUG, "P2P: Missing WFD Requested Device "
1870 "Role");
1871 return;
1872 }
1873
1874 if (wpabuf_tailroom(resp) < 5)
1875 return;
1876
1877 pos = query;
1878 role = *pos++;
1879 wpa_printf(MSG_DEBUG, "P2P: WSD for device role 0x%x", role);
1880
1881 /* TODO: role specific handling */
1882
1883 /* Length (to be filled) */
1884 len_pos = wpabuf_put(resp, 2);
1885 wpabuf_put_u8(resp, P2P_SERV_WIFI_DISPLAY);
1886 wpabuf_put_u8(resp, srv_trans_id);
1887 wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Status Code */
1888
1889 while (pos < query + query_len) {
1890 if (*pos < MAX_WFD_SUBELEMS &&
1891 wpa_s->global->wfd_subelem[*pos] &&
1892 wpabuf_tailroom(resp) >=
1893 wpabuf_len(wpa_s->global->wfd_subelem[*pos])) {
1894 wpa_printf(MSG_DEBUG, "P2P: Add WSD response "
1895 "subelement %u", *pos);
1896 wpabuf_put_buf(resp, wpa_s->global->wfd_subelem[*pos]);
1897 }
1898 pos++;
1899 }
1900
1901 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
1902}
1903#endif /* CONFIG_WIFI_DISPLAY */
1904
1905
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001906void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
1907 u16 update_indic, const u8 *tlvs, size_t tlvs_len)
1908{
1909 struct wpa_supplicant *wpa_s = ctx;
1910 const u8 *pos = tlvs;
1911 const u8 *end = tlvs + tlvs_len;
1912 const u8 *tlv_end;
1913 u16 slen;
1914 struct wpabuf *resp;
1915 u8 srv_proto, srv_trans_id;
1916 size_t buf_len;
1917 char *buf;
1918
1919 wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Request TLVs",
1920 tlvs, tlvs_len);
1921 buf_len = 2 * tlvs_len + 1;
1922 buf = os_malloc(buf_len);
1923 if (buf) {
1924 wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
1925 wpa_msg_ctrl(wpa_s, MSG_INFO, P2P_EVENT_SERV_DISC_REQ "%d "
1926 MACSTR " %u %u %s",
1927 freq, MAC2STR(sa), dialog_token, update_indic,
1928 buf);
1929 os_free(buf);
1930 }
1931
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001932 if (wpa_s->p2p_sd_over_ctrl_iface) {
1933 wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
1934 update_indic, tlvs, tlvs_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001935 return; /* to be processed by an external program */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001936 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001937
1938 resp = wpabuf_alloc(10000);
1939 if (resp == NULL)
1940 return;
1941
1942 while (pos + 1 < end) {
1943 wpa_printf(MSG_DEBUG, "P2P: Service Request TLV");
1944 slen = WPA_GET_LE16(pos);
1945 pos += 2;
1946 if (pos + slen > end || slen < 2) {
1947 wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data "
1948 "length");
1949 wpabuf_free(resp);
1950 return;
1951 }
1952 tlv_end = pos + slen;
1953
1954 srv_proto = *pos++;
1955 wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
1956 srv_proto);
1957 srv_trans_id = *pos++;
1958 wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
1959 srv_trans_id);
1960
1961 wpa_hexdump(MSG_MSGDUMP, "P2P: Query Data",
1962 pos, tlv_end - pos);
1963
1964
1965 if (wpa_s->force_long_sd) {
1966 wpa_printf(MSG_DEBUG, "P2P: SD test - force long "
1967 "response");
1968 wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
1969 wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
1970 goto done;
1971 }
1972
1973 switch (srv_proto) {
1974 case P2P_SERV_ALL_SERVICES:
1975 wpa_printf(MSG_DEBUG, "P2P: Service Discovery Request "
1976 "for all services");
1977 if (dl_list_empty(&wpa_s->global->p2p_srv_upnp) &&
1978 dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
1979 wpa_printf(MSG_DEBUG, "P2P: No service "
1980 "discovery protocols available");
1981 wpas_sd_add_proto_not_avail(
1982 resp, P2P_SERV_ALL_SERVICES,
1983 srv_trans_id);
1984 break;
1985 }
1986 wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
1987 wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
1988 break;
1989 case P2P_SERV_BONJOUR:
1990 wpas_sd_req_bonjour(wpa_s, resp, srv_trans_id,
1991 pos, tlv_end - pos);
1992 break;
1993 case P2P_SERV_UPNP:
1994 wpas_sd_req_upnp(wpa_s, resp, srv_trans_id,
1995 pos, tlv_end - pos);
1996 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001997#ifdef CONFIG_WIFI_DISPLAY
1998 case P2P_SERV_WIFI_DISPLAY:
1999 wpas_sd_req_wfd(wpa_s, resp, srv_trans_id,
2000 pos, tlv_end - pos);
2001 break;
2002#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002003 default:
2004 wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
2005 "protocol %u", srv_proto);
2006 wpas_sd_add_proto_not_avail(resp, srv_proto,
2007 srv_trans_id);
2008 break;
2009 }
2010
2011 pos = tlv_end;
2012 }
2013
2014done:
2015 wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
2016 update_indic, tlvs, tlvs_len);
2017
2018 wpas_p2p_sd_response(wpa_s, freq, sa, dialog_token, resp);
2019
2020 wpabuf_free(resp);
2021}
2022
2023
2024void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
2025 const u8 *tlvs, size_t tlvs_len)
2026{
2027 struct wpa_supplicant *wpa_s = ctx;
2028 const u8 *pos = tlvs;
2029 const u8 *end = tlvs + tlvs_len;
2030 const u8 *tlv_end;
2031 u16 slen;
2032 size_t buf_len;
2033 char *buf;
2034
2035 wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Response TLVs",
2036 tlvs, tlvs_len);
2037 if (tlvs_len > 1500) {
2038 /* TODO: better way for handling this */
2039 wpa_msg_ctrl(wpa_s, MSG_INFO,
2040 P2P_EVENT_SERV_DISC_RESP MACSTR
2041 " %u <long response: %u bytes>",
2042 MAC2STR(sa), update_indic,
2043 (unsigned int) tlvs_len);
2044 } else {
2045 buf_len = 2 * tlvs_len + 1;
2046 buf = os_malloc(buf_len);
2047 if (buf) {
2048 wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
2049 wpa_msg_ctrl(wpa_s, MSG_INFO,
2050 P2P_EVENT_SERV_DISC_RESP MACSTR " %u %s",
2051 MAC2STR(sa), update_indic, buf);
2052 os_free(buf);
2053 }
2054 }
2055
2056 while (pos < end) {
2057 u8 srv_proto, srv_trans_id, status;
2058
2059 wpa_printf(MSG_DEBUG, "P2P: Service Response TLV");
2060 slen = WPA_GET_LE16(pos);
2061 pos += 2;
2062 if (pos + slen > end || slen < 3) {
2063 wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data "
2064 "length");
2065 return;
2066 }
2067 tlv_end = pos + slen;
2068
2069 srv_proto = *pos++;
2070 wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
2071 srv_proto);
2072 srv_trans_id = *pos++;
2073 wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
2074 srv_trans_id);
2075 status = *pos++;
2076 wpa_printf(MSG_DEBUG, "P2P: Status Code ID %u",
2077 status);
2078
2079 wpa_hexdump(MSG_MSGDUMP, "P2P: Response Data",
2080 pos, tlv_end - pos);
2081
2082 pos = tlv_end;
2083 }
2084
2085 wpas_notify_p2p_sd_response(wpa_s, sa, update_indic, tlvs, tlvs_len);
2086}
2087
2088
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002089u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
2090 const struct wpabuf *tlvs)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002091{
2092 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002093 return wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002094 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002095 return 0;
2096 return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002097}
2098
2099
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002100u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
2101 u8 version, const char *query)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002102{
2103 struct wpabuf *tlvs;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002104 u64 ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002105
2106 tlvs = wpabuf_alloc(2 + 1 + 1 + 1 + os_strlen(query));
2107 if (tlvs == NULL)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002108 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002109 wpabuf_put_le16(tlvs, 1 + 1 + 1 + os_strlen(query));
2110 wpabuf_put_u8(tlvs, P2P_SERV_UPNP); /* Service Protocol Type */
2111 wpabuf_put_u8(tlvs, 1); /* Service Transaction ID */
2112 wpabuf_put_u8(tlvs, version);
2113 wpabuf_put_str(tlvs, query);
2114 ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
2115 wpabuf_free(tlvs);
2116 return ret;
2117}
2118
2119
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002120#ifdef CONFIG_WIFI_DISPLAY
2121
2122static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
2123 const struct wpabuf *tlvs)
2124{
2125 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
2126 return 0;
2127 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
2128 return 0;
2129 return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
2130}
2131
2132
2133#define MAX_WFD_SD_SUBELEMS 20
2134
2135static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role,
2136 const char *subelems)
2137{
2138 u8 *len;
2139 const char *pos;
2140 int val;
2141 int count = 0;
2142
2143 len = wpabuf_put(tlvs, 2);
2144 wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */
2145 wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
2146
2147 wpabuf_put_u8(tlvs, role);
2148
2149 pos = subelems;
2150 while (*pos) {
2151 val = atoi(pos);
2152 if (val >= 0 && val < 256) {
2153 wpabuf_put_u8(tlvs, val);
2154 count++;
2155 if (count == MAX_WFD_SD_SUBELEMS)
2156 break;
2157 }
2158 pos = os_strchr(pos + 1, ',');
2159 if (pos == NULL)
2160 break;
2161 pos++;
2162 }
2163
2164 WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2);
2165}
2166
2167
2168u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
2169 const u8 *dst, const char *role)
2170{
2171 struct wpabuf *tlvs;
2172 u64 ret;
2173 const char *subelems;
2174 u8 id = 1;
2175
2176 subelems = os_strchr(role, ' ');
2177 if (subelems == NULL)
2178 return 0;
2179 subelems++;
2180
2181 tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS));
2182 if (tlvs == NULL)
2183 return 0;
2184
2185 if (os_strstr(role, "[source]"))
2186 wfd_add_sd_req_role(tlvs, id++, 0x00, subelems);
2187 if (os_strstr(role, "[pri-sink]"))
2188 wfd_add_sd_req_role(tlvs, id++, 0x01, subelems);
2189 if (os_strstr(role, "[sec-sink]"))
2190 wfd_add_sd_req_role(tlvs, id++, 0x02, subelems);
2191 if (os_strstr(role, "[source+sink]"))
2192 wfd_add_sd_req_role(tlvs, id++, 0x03, subelems);
2193
2194 ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs);
2195 wpabuf_free(tlvs);
2196 return ret;
2197}
2198
2199#endif /* CONFIG_WIFI_DISPLAY */
2200
2201
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002202int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002203{
2204 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002205 return wpa_drv_p2p_sd_cancel_request(wpa_s, req);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002206 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
2207 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002208 return p2p_sd_cancel_request(wpa_s->global->p2p,
2209 (void *) (uintptr_t) req);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002210}
2211
2212
2213void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
2214 const u8 *dst, u8 dialog_token,
2215 const struct wpabuf *resp_tlvs)
2216{
2217 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
2218 wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token,
2219 resp_tlvs);
2220 return;
2221 }
2222 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
2223 return;
2224 p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
2225 resp_tlvs);
2226}
2227
Dmitry Shmidteaf261d2013-08-14 15:30:08 -07002228
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002229void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
2230{
2231 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
2232 wpa_drv_p2p_service_update(wpa_s);
2233 return;
2234 }
2235 if (wpa_s->global->p2p)
2236 p2p_sd_service_update(wpa_s->global->p2p);
2237}
2238
2239
2240static void wpas_p2p_srv_bonjour_free(struct p2p_srv_bonjour *bsrv)
2241{
2242 dl_list_del(&bsrv->list);
2243 wpabuf_free(bsrv->query);
2244 wpabuf_free(bsrv->resp);
2245 os_free(bsrv);
2246}
2247
2248
2249static void wpas_p2p_srv_upnp_free(struct p2p_srv_upnp *usrv)
2250{
2251 dl_list_del(&usrv->list);
2252 os_free(usrv->service);
2253 os_free(usrv);
2254}
2255
2256
2257void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s)
2258{
2259 struct p2p_srv_bonjour *bsrv, *bn;
2260 struct p2p_srv_upnp *usrv, *un;
2261
2262 dl_list_for_each_safe(bsrv, bn, &wpa_s->global->p2p_srv_bonjour,
2263 struct p2p_srv_bonjour, list)
2264 wpas_p2p_srv_bonjour_free(bsrv);
2265
2266 dl_list_for_each_safe(usrv, un, &wpa_s->global->p2p_srv_upnp,
2267 struct p2p_srv_upnp, list)
2268 wpas_p2p_srv_upnp_free(usrv);
2269
2270 wpas_p2p_sd_service_update(wpa_s);
2271}
2272
2273
2274int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
2275 struct wpabuf *query, struct wpabuf *resp)
2276{
2277 struct p2p_srv_bonjour *bsrv;
2278
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002279 bsrv = os_zalloc(sizeof(*bsrv));
2280 if (bsrv == NULL)
2281 return -1;
2282 bsrv->query = query;
2283 bsrv->resp = resp;
2284 dl_list_add(&wpa_s->global->p2p_srv_bonjour, &bsrv->list);
2285
2286 wpas_p2p_sd_service_update(wpa_s);
2287 return 0;
2288}
2289
2290
2291int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s,
2292 const struct wpabuf *query)
2293{
2294 struct p2p_srv_bonjour *bsrv;
2295
2296 bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
2297 if (bsrv == NULL)
2298 return -1;
2299 wpas_p2p_srv_bonjour_free(bsrv);
2300 wpas_p2p_sd_service_update(wpa_s);
2301 return 0;
2302}
2303
2304
2305int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
2306 const char *service)
2307{
2308 struct p2p_srv_upnp *usrv;
2309
2310 if (wpas_p2p_service_get_upnp(wpa_s, version, service))
2311 return 0; /* Already listed */
2312 usrv = os_zalloc(sizeof(*usrv));
2313 if (usrv == NULL)
2314 return -1;
2315 usrv->version = version;
2316 usrv->service = os_strdup(service);
2317 if (usrv->service == NULL) {
2318 os_free(usrv);
2319 return -1;
2320 }
2321 dl_list_add(&wpa_s->global->p2p_srv_upnp, &usrv->list);
2322
2323 wpas_p2p_sd_service_update(wpa_s);
2324 return 0;
2325}
2326
2327
2328int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
2329 const char *service)
2330{
2331 struct p2p_srv_upnp *usrv;
2332
2333 usrv = wpas_p2p_service_get_upnp(wpa_s, version, service);
2334 if (usrv == NULL)
2335 return -1;
2336 wpas_p2p_srv_upnp_free(usrv);
2337 wpas_p2p_sd_service_update(wpa_s);
2338 return 0;
2339}
2340
2341
2342static void wpas_prov_disc_local_display(struct wpa_supplicant *wpa_s,
2343 const u8 *peer, const char *params,
2344 unsigned int generated_pin)
2345{
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002346 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR
2347 " %08d%s", MAC2STR(peer), generated_pin, params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002348}
2349
2350
2351static void wpas_prov_disc_local_keypad(struct wpa_supplicant *wpa_s,
2352 const u8 *peer, const char *params)
2353{
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002354 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR
2355 "%s", MAC2STR(peer), params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002356}
2357
2358
2359void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
2360 const u8 *dev_addr, const u8 *pri_dev_type,
2361 const char *dev_name, u16 supp_config_methods,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002362 u8 dev_capab, u8 group_capab, const u8 *group_id,
2363 size_t group_id_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002364{
2365 struct wpa_supplicant *wpa_s = ctx;
2366 char devtype[WPS_DEV_TYPE_BUFSIZE];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002367 char params[300];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002368 u8 empty_dev_type[8];
2369 unsigned int generated_pin = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002370 struct wpa_supplicant *group = NULL;
2371
2372 if (group_id) {
2373 for (group = wpa_s->global->ifaces; group; group = group->next)
2374 {
2375 struct wpa_ssid *s = group->current_ssid;
2376 if (s != NULL &&
2377 s->mode == WPAS_MODE_P2P_GO &&
2378 group_id_len - ETH_ALEN == s->ssid_len &&
2379 os_memcmp(group_id + ETH_ALEN, s->ssid,
2380 s->ssid_len) == 0)
2381 break;
2382 }
2383 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002384
2385 if (pri_dev_type == NULL) {
2386 os_memset(empty_dev_type, 0, sizeof(empty_dev_type));
2387 pri_dev_type = empty_dev_type;
2388 }
2389 os_snprintf(params, sizeof(params), " p2p_dev_addr=" MACSTR
2390 " pri_dev_type=%s name='%s' config_methods=0x%x "
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002391 "dev_capab=0x%x group_capab=0x%x%s%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002392 MAC2STR(dev_addr),
2393 wps_dev_type_bin2str(pri_dev_type, devtype,
2394 sizeof(devtype)),
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002395 dev_name, supp_config_methods, dev_capab, group_capab,
2396 group ? " group=" : "",
2397 group ? group->ifname : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002398 params[sizeof(params) - 1] = '\0';
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002399
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002400 if (config_methods & WPS_CONFIG_DISPLAY) {
2401 generated_pin = wps_generate_pin();
2402 wpas_prov_disc_local_display(wpa_s, peer, params,
2403 generated_pin);
2404 } else if (config_methods & WPS_CONFIG_KEYPAD)
2405 wpas_prov_disc_local_keypad(wpa_s, peer, params);
2406 else if (config_methods & WPS_CONFIG_PUSHBUTTON)
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002407 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ
2408 MACSTR "%s", MAC2STR(peer), params);
Jouni Malinen75ecf522011-06-27 15:19:46 -07002409
2410 wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */,
2411 P2P_PROV_DISC_SUCCESS,
2412 config_methods, generated_pin);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002413}
2414
2415
2416void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
2417{
2418 struct wpa_supplicant *wpa_s = ctx;
2419 unsigned int generated_pin = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002420 char params[20];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002421
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002422 if (wpa_s->pending_pd_before_join &&
2423 (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
2424 os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
2425 wpa_s->pending_pd_before_join = 0;
2426 wpa_printf(MSG_DEBUG, "P2P: Starting pending "
2427 "join-existing-group operation");
2428 wpas_p2p_join_start(wpa_s);
2429 return;
2430 }
2431
Dmitry Shmidt04949592012-07-19 12:16:46 -07002432 if (wpa_s->pending_pd_use == AUTO_PD_JOIN ||
2433 wpa_s->pending_pd_use == AUTO_PD_GO_NEG)
2434 os_snprintf(params, sizeof(params), " peer_go=%d",
2435 wpa_s->pending_pd_use == AUTO_PD_JOIN);
2436 else
2437 params[0] = '\0';
2438
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002439 if (config_methods & WPS_CONFIG_DISPLAY)
Dmitry Shmidt04949592012-07-19 12:16:46 -07002440 wpas_prov_disc_local_keypad(wpa_s, peer, params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002441 else if (config_methods & WPS_CONFIG_KEYPAD) {
2442 generated_pin = wps_generate_pin();
Dmitry Shmidt04949592012-07-19 12:16:46 -07002443 wpas_prov_disc_local_display(wpa_s, peer, params,
2444 generated_pin);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002445 } else if (config_methods & WPS_CONFIG_PUSHBUTTON)
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002446 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP
2447 MACSTR "%s", MAC2STR(peer), params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002448
Jouni Malinen75ecf522011-06-27 15:19:46 -07002449 wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
2450 P2P_PROV_DISC_SUCCESS,
2451 config_methods, generated_pin);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002452}
2453
2454
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002455static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
2456 enum p2p_prov_disc_status status)
Jouni Malinen75ecf522011-06-27 15:19:46 -07002457{
2458 struct wpa_supplicant *wpa_s = ctx;
2459
Dmitry Shmidt04949592012-07-19 12:16:46 -07002460 if (wpa_s->p2p_fallback_to_go_neg) {
2461 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto "
2462 "failed - fall back to GO Negotiation");
2463 wpas_p2p_fallback_to_go_neg(wpa_s, 0);
2464 return;
2465 }
2466
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002467 if (status == P2P_PROV_DISC_TIMEOUT_JOIN) {
Dmitry Shmidt2b380482012-09-13 10:52:13 -07002468 wpa_s->pending_pd_before_join = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002469 wpa_printf(MSG_DEBUG, "P2P: Starting pending "
2470 "join-existing-group operation (no ACK for PD "
2471 "Req attempts)");
2472 wpas_p2p_join_start(wpa_s);
2473 return;
Dmitry Shmidt2b380482012-09-13 10:52:13 -07002474 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002475
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002476 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
2477 " p2p_dev_addr=" MACSTR " status=%d",
2478 MAC2STR(peer), status);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002479
Jouni Malinen75ecf522011-06-27 15:19:46 -07002480 wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
2481 status, 0, 0);
2482}
2483
2484
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07002485static int freq_included(const struct p2p_channels *channels, unsigned int freq)
2486{
2487 if (channels == NULL)
2488 return 1; /* Assume no restrictions */
2489 return p2p_channels_includes_freq(channels, freq);
2490
2491}
2492
2493
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002494static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
2495 const u8 *go_dev_addr, const u8 *ssid,
2496 size_t ssid_len, int *go, u8 *group_bssid,
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07002497 int *force_freq, int persistent_group,
2498 const struct p2p_channels *channels)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002499{
2500 struct wpa_supplicant *wpa_s = ctx;
2501 struct wpa_ssid *s;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002502 int res;
2503 struct wpa_supplicant *grp;
2504
2505 if (!persistent_group) {
2506 wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
2507 " to join an active group", MAC2STR(sa));
2508 if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
2509 (os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN)
2510 == 0 ||
2511 os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0)) {
2512 wpa_printf(MSG_DEBUG, "P2P: Accept previously "
2513 "authorized invitation");
2514 goto accept_inv;
2515 }
2516 /*
2517 * Do not accept the invitation automatically; notify user and
2518 * request approval.
2519 */
2520 return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
2521 }
2522
2523 grp = wpas_get_p2p_group(wpa_s, ssid, ssid_len, go);
2524 if (grp) {
2525 wpa_printf(MSG_DEBUG, "P2P: Accept invitation to already "
2526 "running persistent group");
2527 if (*go)
2528 os_memcpy(group_bssid, grp->own_addr, ETH_ALEN);
2529 goto accept_inv;
2530 }
2531
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08002532 if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
2533 os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0) {
2534 wpa_printf(MSG_DEBUG, "P2P: Accept previously initiated "
2535 "invitation to re-invoke a persistent group");
2536 } else if (!wpa_s->conf->persistent_reconnect)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002537 return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
2538
2539 for (s = wpa_s->conf->ssid; s; s = s->next) {
2540 if (s->disabled == 2 &&
2541 os_memcmp(s->bssid, go_dev_addr, ETH_ALEN) == 0 &&
2542 s->ssid_len == ssid_len &&
2543 os_memcmp(ssid, s->ssid, ssid_len) == 0)
2544 break;
2545 }
2546
2547 if (!s) {
2548 wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
2549 " requested reinvocation of an unknown group",
2550 MAC2STR(sa));
2551 return P2P_SC_FAIL_UNKNOWN_GROUP;
2552 }
2553
2554 if (s->mode == WPAS_MODE_P2P_GO && !wpas_p2p_create_iface(wpa_s)) {
2555 *go = 1;
2556 if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
2557 wpa_printf(MSG_DEBUG, "P2P: The only available "
2558 "interface is already in use - reject "
2559 "invitation");
2560 return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
2561 }
2562 os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
2563 } else if (s->mode == WPAS_MODE_P2P_GO) {
2564 *go = 1;
2565 if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO) < 0)
2566 {
2567 wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
2568 "interface address for the group");
2569 return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
2570 }
2571 os_memcpy(group_bssid, wpa_s->pending_interface_addr,
2572 ETH_ALEN);
2573 }
2574
2575accept_inv:
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002576 wpas_p2p_set_own_freq_preference(wpa_s, 0);
2577
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07002578 /* Get one of the frequencies currently in use */
2579 if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) {
2580 wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match a channel already used by one of the interfaces");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002581 *force_freq = res;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002582 wpas_p2p_set_own_freq_preference(wpa_s, res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002583 }
2584
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07002585 if (*force_freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
2586 wpas_p2p_num_unused_channels(wpa_s) > 0) {
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07002587 if (*go == 0) {
2588 /* We are the client */
2589 wpa_printf(MSG_DEBUG, "P2P: Peer was found to be "
2590 "running a GO but we are capable of MCC, "
2591 "figure out the best channel to use");
2592 *force_freq = 0;
2593 } else if (!freq_included(channels, *force_freq)) {
2594 /* We are the GO, and *force_freq is not in the
2595 * intersection */
2596 wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
2597 "in intersection but we are capable of MCC, "
2598 "figure out the best channel to use",
2599 *force_freq);
2600 *force_freq = 0;
2601 }
2602 }
2603
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002604 return P2P_SC_SUCCESS;
2605}
2606
2607
2608static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
2609 const u8 *ssid, size_t ssid_len,
2610 const u8 *go_dev_addr, u8 status,
2611 int op_freq)
2612{
2613 struct wpa_supplicant *wpa_s = ctx;
2614 struct wpa_ssid *s;
2615
2616 for (s = wpa_s->conf->ssid; s; s = s->next) {
2617 if (s->disabled == 2 &&
2618 s->ssid_len == ssid_len &&
2619 os_memcmp(ssid, s->ssid, ssid_len) == 0)
2620 break;
2621 }
2622
2623 if (status == P2P_SC_SUCCESS) {
2624 wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
2625 " was accepted; op_freq=%d MHz",
2626 MAC2STR(sa), op_freq);
2627 if (s) {
Dmitry Shmidt91c40cd2012-09-25 14:23:53 -07002628 int go = s->mode == WPAS_MODE_P2P_GO;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002629 wpas_p2p_group_add_persistent(
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08002630 wpa_s, s, go, go ? op_freq : 0, 0, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002631 } else if (bssid) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002632 wpa_s->user_initiated_pd = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002633 wpas_p2p_join(wpa_s, bssid, go_dev_addr,
Dmitry Shmidt04949592012-07-19 12:16:46 -07002634 wpa_s->p2p_wps_method, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002635 }
2636 return;
2637 }
2638
2639 if (status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
2640 wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
2641 " was rejected (status %u)", MAC2STR(sa), status);
2642 return;
2643 }
2644
2645 if (!s) {
2646 if (bssid) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002647 wpa_msg_global(wpa_s, MSG_INFO,
2648 P2P_EVENT_INVITATION_RECEIVED
2649 "sa=" MACSTR " go_dev_addr=" MACSTR
2650 " bssid=" MACSTR " unknown-network",
2651 MAC2STR(sa), MAC2STR(go_dev_addr),
2652 MAC2STR(bssid));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002653 } else {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002654 wpa_msg_global(wpa_s, MSG_INFO,
2655 P2P_EVENT_INVITATION_RECEIVED
2656 "sa=" MACSTR " go_dev_addr=" MACSTR
2657 " unknown-network",
2658 MAC2STR(sa), MAC2STR(go_dev_addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002659 }
2660 return;
2661 }
2662
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08002663 if (s->mode == WPAS_MODE_P2P_GO && op_freq) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002664 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
2665 "sa=" MACSTR " persistent=%d freq=%d",
2666 MAC2STR(sa), s->id, op_freq);
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08002667 } else {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002668 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
2669 "sa=" MACSTR " persistent=%d",
2670 MAC2STR(sa), s->id);
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08002671 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002672}
2673
2674
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002675static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
2676 struct wpa_ssid *ssid,
2677 const u8 *peer)
2678{
2679 size_t i;
2680
2681 if (ssid == NULL)
2682 return;
2683
2684 for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) {
2685 if (os_memcmp(ssid->p2p_client_list + i * ETH_ALEN, peer,
2686 ETH_ALEN) == 0)
2687 break;
2688 }
2689 if (i >= ssid->num_p2p_clients) {
2690 if (ssid->mode != WPAS_MODE_P2P_GO &&
2691 os_memcmp(ssid->bssid, peer, ETH_ALEN) == 0) {
2692 wpa_printf(MSG_DEBUG, "P2P: Remove persistent group %d "
2693 "due to invitation result", ssid->id);
2694 wpas_notify_network_removed(wpa_s, ssid);
2695 wpa_config_remove_network(wpa_s->conf, ssid->id);
2696 return;
2697 }
2698 return; /* Peer not found in client list */
2699 }
2700
2701 wpa_printf(MSG_DEBUG, "P2P: Remove peer " MACSTR " from persistent "
2702 "group %d client list due to invitation result",
2703 MAC2STR(peer), ssid->id);
2704 os_memmove(ssid->p2p_client_list + i * ETH_ALEN,
2705 ssid->p2p_client_list + (i + 1) * ETH_ALEN,
2706 (ssid->num_p2p_clients - i - 1) * ETH_ALEN);
2707 ssid->num_p2p_clients--;
2708#ifndef CONFIG_NO_CONFIG_WRITE
2709 if (wpa_s->parent->conf->update_config &&
2710 wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
2711 wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
2712#endif /* CONFIG_NO_CONFIG_WRITE */
2713}
2714
2715
2716static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s,
2717 const u8 *peer)
2718{
2719 struct wpa_ssid *ssid;
2720
2721 wpa_s = wpa_s->global->p2p_invite_group;
2722 if (wpa_s == NULL)
2723 return; /* No known invitation group */
2724 ssid = wpa_s->current_ssid;
2725 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
2726 !ssid->p2p_persistent_group)
2727 return; /* Not operating as a GO in persistent group */
2728 ssid = wpas_p2p_get_persistent(wpa_s->parent, peer,
2729 ssid->ssid, ssid->ssid_len);
2730 wpas_remove_persistent_peer(wpa_s, ssid, peer);
2731}
2732
2733
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08002734static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002735 const struct p2p_channels *channels,
2736 const u8 *peer)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002737{
2738 struct wpa_supplicant *wpa_s = ctx;
2739 struct wpa_ssid *ssid;
2740
2741 if (bssid) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002742 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
2743 "status=%d " MACSTR,
2744 status, MAC2STR(bssid));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002745 } else {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002746 wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
2747 "status=%d ", status);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002748 }
2749 wpas_notify_p2p_invitation_result(wpa_s, status, bssid);
2750
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002751 wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR,
2752 status, MAC2STR(peer));
2753 if (wpa_s->pending_invite_ssid_id == -1) {
2754 if (status == P2P_SC_FAIL_UNKNOWN_GROUP)
2755 wpas_remove_persistent_client(wpa_s, peer);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002756 return; /* Invitation to active group */
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002757 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002758
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08002759 if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
2760 wpa_printf(MSG_DEBUG, "P2P: Waiting for peer to start another "
2761 "invitation exchange to indicate readiness for "
2762 "re-invocation");
2763 }
2764
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002765 if (status != P2P_SC_SUCCESS) {
Dmitry Shmidt700a1372013-03-15 14:14:44 -07002766 if (status == P2P_SC_FAIL_UNKNOWN_GROUP) {
2767 ssid = wpa_config_get_network(
2768 wpa_s->conf, wpa_s->pending_invite_ssid_id);
2769 wpas_remove_persistent_peer(wpa_s, ssid, peer);
2770 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002771 wpas_p2p_remove_pending_group_interface(wpa_s);
2772 return;
2773 }
2774
2775 ssid = wpa_config_get_network(wpa_s->conf,
2776 wpa_s->pending_invite_ssid_id);
2777 if (ssid == NULL) {
2778 wpa_printf(MSG_ERROR, "P2P: Could not find persistent group "
2779 "data matching with invitation");
2780 return;
2781 }
2782
Jouni Malinen2c5b17d2012-10-13 21:52:46 -07002783 /*
2784 * The peer could have missed our ctrl::ack frame for Invitation
2785 * Response and continue retransmitting the frame. To reduce the
2786 * likelihood of the peer not getting successful TX status for the
2787 * Invitation Response frame, wait a short time here before starting
2788 * the persistent group so that we will remain on the current channel to
2789 * acknowledge any possible retransmission from the peer.
2790 */
Irfan Sheriff81931b82012-10-16 21:40:46 -07002791#ifndef ANDROID_P2P
Jouni Malinen2c5b17d2012-10-13 21:52:46 -07002792 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 50 ms wait on current channel before "
2793 "starting persistent group");
2794 os_sleep(0, 50000);
Irfan Sheriff81931b82012-10-16 21:40:46 -07002795#else
2796 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 100 ms wait on current channel before "
2797 "starting persistent group");
2798 os_sleep(0, 100000);
2799#endif
Jouni Malinen2c5b17d2012-10-13 21:52:46 -07002800
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002801 wpas_p2p_group_add_persistent(wpa_s, ssid,
Jouni Malinen31be0a42012-08-31 21:20:51 +03002802 ssid->mode == WPAS_MODE_P2P_GO,
2803 wpa_s->p2p_persistent_go_freq,
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08002804 wpa_s->p2p_go_ht40, channels);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002805}
2806
2807
Dmitry Shmidt04949592012-07-19 12:16:46 -07002808static int wpas_p2p_disallowed_freq(struct wpa_global *global,
2809 unsigned int freq)
2810{
2811 unsigned int i;
2812
2813 if (global->p2p_disallow_freq == NULL)
2814 return 0;
2815
2816 for (i = 0; i < global->num_p2p_disallow_freq; i++) {
2817 if (freq >= global->p2p_disallow_freq[i].min &&
2818 freq <= global->p2p_disallow_freq[i].max)
2819 return 1;
2820 }
2821
2822 return 0;
2823}
2824
2825
2826static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan)
2827{
2828 reg->channel[reg->channels] = chan;
2829 reg->channels++;
2830}
2831
2832
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002833static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
2834 struct p2p_channels *chan)
2835{
2836 int i, cla = 0;
2837
2838 wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
2839 "band");
2840
2841 /* Operating class 81 - 2.4 GHz band channels 1..13 */
2842 chan->reg_class[cla].reg_class = 81;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002843 chan->reg_class[cla].channels = 0;
2844 for (i = 0; i < 11; i++) {
2845 if (!wpas_p2p_disallowed_freq(wpa_s->global, 2412 + i * 5))
2846 wpas_p2p_add_chan(&chan->reg_class[cla], i + 1);
2847 }
2848 if (chan->reg_class[cla].channels)
2849 cla++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002850
2851 wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for lower 5 GHz "
2852 "band");
2853
2854 /* Operating class 115 - 5 GHz, channels 36-48 */
2855 chan->reg_class[cla].reg_class = 115;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002856 chan->reg_class[cla].channels = 0;
2857 if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 36 * 5))
2858 wpas_p2p_add_chan(&chan->reg_class[cla], 36);
2859 if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 40 * 5))
2860 wpas_p2p_add_chan(&chan->reg_class[cla], 40);
2861 if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 44 * 5))
2862 wpas_p2p_add_chan(&chan->reg_class[cla], 44);
2863 if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 48 * 5))
2864 wpas_p2p_add_chan(&chan->reg_class[cla], 48);
2865 if (chan->reg_class[cla].channels)
2866 cla++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002867
2868 wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for higher 5 GHz "
2869 "band");
2870
2871 /* Operating class 124 - 5 GHz, channels 149,153,157,161 */
2872 chan->reg_class[cla].reg_class = 124;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002873 chan->reg_class[cla].channels = 0;
2874 if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 149 * 5))
2875 wpas_p2p_add_chan(&chan->reg_class[cla], 149);
2876 if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 153 * 5))
2877 wpas_p2p_add_chan(&chan->reg_class[cla], 153);
2878 if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 156 * 5))
2879 wpas_p2p_add_chan(&chan->reg_class[cla], 157);
2880 if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 161 * 5))
2881 wpas_p2p_add_chan(&chan->reg_class[cla], 161);
2882 if (chan->reg_class[cla].channels)
2883 cla++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002884
2885 chan->reg_classes = cla;
2886 return 0;
2887}
2888
2889
2890static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
2891 u16 num_modes,
2892 enum hostapd_hw_mode mode)
2893{
2894 u16 i;
2895
2896 for (i = 0; i < num_modes; i++) {
2897 if (modes[i].mode == mode)
2898 return &modes[i];
2899 }
2900
2901 return NULL;
2902}
2903
2904
Dmitry Shmidt04949592012-07-19 12:16:46 -07002905static int has_channel(struct wpa_global *global,
2906 struct hostapd_hw_modes *mode, u8 chan, int *flags)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002907{
2908 int i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002909 unsigned int freq;
2910
2911 freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
2912 chan * 5;
2913 if (wpas_p2p_disallowed_freq(global, freq))
2914 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002915
2916 for (i = 0; i < mode->num_channels; i++) {
2917 if (mode->channels[i].chan == chan) {
2918 if (flags)
2919 *flags = mode->channels[i].flag;
2920 return !(mode->channels[i].flag &
2921 (HOSTAPD_CHAN_DISABLED |
2922 HOSTAPD_CHAN_PASSIVE_SCAN |
2923 HOSTAPD_CHAN_NO_IBSS |
2924 HOSTAPD_CHAN_RADAR));
2925 }
2926 }
2927
2928 return 0;
2929}
2930
2931
2932struct p2p_oper_class_map {
2933 enum hostapd_hw_mode mode;
2934 u8 op_class;
2935 u8 min_chan;
2936 u8 max_chan;
2937 u8 inc;
2938 enum { BW20, BW40PLUS, BW40MINUS } bw;
2939};
2940
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002941static struct p2p_oper_class_map op_class[] = {
2942 { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002943#if 0 /* Do not enable HT40 on 2 GHz for now */
2944 { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
2945 { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
2946#endif
2947 { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
2948 { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
2949 { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
2950 { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
2951 { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
2952 { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
2953 { -1, 0, 0, 0, 0, BW20 }
2954};
2955
2956
2957static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
2958 struct hostapd_hw_modes *mode,
2959 u8 channel, u8 bw)
2960{
2961 int flag;
2962
2963 if (!has_channel(wpa_s->global, mode, channel, &flag))
2964 return -1;
2965 if (bw == BW40MINUS &&
2966 (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
2967 !has_channel(wpa_s->global, mode, channel - 4, NULL)))
2968 return 0;
2969 if (bw == BW40PLUS &&
2970 (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
2971 !has_channel(wpa_s->global, mode, channel + 4, NULL)))
2972 return 0;
2973 return 1;
2974}
2975
2976
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002977static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
2978 struct p2p_channels *chan)
2979{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002980 struct hostapd_hw_modes *mode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002981 int cla, op;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002982
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002983 if (wpa_s->hw.modes == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002984 wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
2985 "of all supported channels; assume dualband "
2986 "support");
2987 return wpas_p2p_default_channels(wpa_s, chan);
2988 }
2989
2990 cla = 0;
2991
2992 for (op = 0; op_class[op].op_class; op++) {
2993 struct p2p_oper_class_map *o = &op_class[op];
2994 u8 ch;
2995 struct p2p_reg_class *reg = NULL;
2996
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002997 mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002998 if (mode == NULL)
2999 continue;
3000 for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003001 if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003002 continue;
3003 if (reg == NULL) {
3004 wpa_printf(MSG_DEBUG, "P2P: Add operating "
3005 "class %u", o->op_class);
3006 reg = &chan->reg_class[cla];
3007 cla++;
3008 reg->reg_class = o->op_class;
3009 }
3010 reg->channel[reg->channels] = ch;
3011 reg->channels++;
3012 }
3013 if (reg) {
3014 wpa_hexdump(MSG_DEBUG, "P2P: Channels",
3015 reg->channel, reg->channels);
3016 }
3017 }
3018
3019 chan->reg_classes = cla;
3020
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003021 return 0;
3022}
3023
3024
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003025int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
3026 struct hostapd_hw_modes *mode, u8 channel)
3027{
3028 int op, ret;
3029
3030 for (op = 0; op_class[op].op_class; op++) {
3031 struct p2p_oper_class_map *o = &op_class[op];
3032 u8 ch;
3033
3034 for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
3035 if (o->mode != HOSTAPD_MODE_IEEE80211A ||
3036 o->bw == BW20 || ch != channel)
3037 continue;
3038 ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
3039 if (ret < 0)
3040 continue;
3041 else if (ret > 0)
3042 return (o->bw == BW40MINUS) ? -1 : 1;
3043 else
3044 return 0;
3045 }
3046 }
3047 return 0;
3048}
3049
3050
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003051static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
3052 size_t buf_len)
3053{
3054 struct wpa_supplicant *wpa_s = ctx;
3055
3056 for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
3057 if (os_memcmp(wpa_s->own_addr, interface_addr, ETH_ALEN) == 0)
3058 break;
3059 }
3060 if (wpa_s == NULL)
3061 return -1;
3062
3063 return wpa_drv_get_noa(wpa_s, buf, buf_len);
3064}
3065
3066
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003067static int wpas_go_connected(void *ctx, const u8 *dev_addr)
3068{
3069 struct wpa_supplicant *wpa_s = ctx;
3070
3071 for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
3072 struct wpa_ssid *ssid = wpa_s->current_ssid;
3073 if (ssid == NULL)
3074 continue;
3075 if (ssid->mode != WPAS_MODE_INFRA)
3076 continue;
3077 if (wpa_s->wpa_state != WPA_COMPLETED &&
3078 wpa_s->wpa_state != WPA_GROUP_HANDSHAKE)
3079 continue;
3080 if (os_memcmp(wpa_s->go_dev_addr, dev_addr, ETH_ALEN) == 0)
3081 return 1;
3082 }
3083
3084 return 0;
3085}
3086
3087
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07003088static void wpas_p2p_debug_print(void *ctx, int level, const char *msg)
3089{
3090 struct wpa_supplicant *wpa_s = ctx;
3091 wpa_msg_global(wpa_s, level, "P2P: %s", msg);
3092}
3093
3094
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003095int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s)
3096{
3097 struct wpa_interface iface;
3098 struct wpa_supplicant *p2pdev_wpa_s;
3099 char ifname[100];
3100 char force_name[100];
3101 int ret;
3102
3103 os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
3104 wpa_s->ifname);
3105 force_name[0] = '\0';
3106 wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
3107 ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
3108 force_name, wpa_s->pending_interface_addr, NULL);
3109 if (ret < 0) {
3110 wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface");
3111 return ret;
3112 }
3113 os_strlcpy(wpa_s->pending_interface_name, ifname,
3114 sizeof(wpa_s->pending_interface_name));
3115
3116 os_memset(&iface, 0, sizeof(iface));
3117 iface.p2p_mgmt = 1;
3118 iface.ifname = wpa_s->pending_interface_name;
3119 iface.driver = wpa_s->driver->name;
3120 iface.driver_param = wpa_s->conf->driver_param;
3121 iface.confname = wpa_s->confname;
3122 p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
3123 if (!p2pdev_wpa_s) {
3124 wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
3125 return -1;
3126 }
3127 p2pdev_wpa_s->parent = wpa_s;
3128
3129 wpa_s->pending_interface_name[0] = '\0';
3130 return 0;
3131}
3132
3133
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003134/**
3135 * wpas_p2p_init - Initialize P2P module for %wpa_supplicant
3136 * @global: Pointer to global data from wpa_supplicant_init()
3137 * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
3138 * Returns: 0 on success, -1 on failure
3139 */
3140int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
3141{
3142 struct p2p_config p2p;
3143 unsigned int r;
3144 int i;
3145
3146 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
3147 return 0;
3148
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003149 if (global->p2p)
3150 return 0;
3151
3152 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
3153 struct p2p_params params;
3154
3155 wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management");
3156 os_memset(&params, 0, sizeof(params));
3157 params.dev_name = wpa_s->conf->device_name;
3158 os_memcpy(params.pri_dev_type, wpa_s->conf->device_type,
3159 WPS_DEV_TYPE_LEN);
3160 params.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
3161 os_memcpy(params.sec_dev_type,
3162 wpa_s->conf->sec_device_type,
3163 params.num_sec_dev_types * WPS_DEV_TYPE_LEN);
3164
3165 if (wpa_drv_p2p_set_params(wpa_s, &params) < 0)
3166 return -1;
3167
3168 return 0;
3169 }
3170
3171 os_memset(&p2p, 0, sizeof(p2p));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003172 p2p.cb_ctx = wpa_s;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07003173 p2p.debug_print = wpas_p2p_debug_print;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003174 p2p.p2p_scan = wpas_p2p_scan;
3175 p2p.send_action = wpas_send_action;
3176 p2p.send_action_done = wpas_send_action_done;
3177 p2p.go_neg_completed = wpas_go_neg_completed;
3178 p2p.go_neg_req_rx = wpas_go_neg_req_rx;
3179 p2p.dev_found = wpas_dev_found;
3180 p2p.dev_lost = wpas_dev_lost;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07003181 p2p.find_stopped = wpas_find_stopped;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003182 p2p.start_listen = wpas_start_listen;
3183 p2p.stop_listen = wpas_stop_listen;
3184 p2p.send_probe_resp = wpas_send_probe_resp;
3185 p2p.sd_request = wpas_sd_request;
3186 p2p.sd_response = wpas_sd_response;
3187 p2p.prov_disc_req = wpas_prov_disc_req;
3188 p2p.prov_disc_resp = wpas_prov_disc_resp;
Jouni Malinen75ecf522011-06-27 15:19:46 -07003189 p2p.prov_disc_fail = wpas_prov_disc_fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003190 p2p.invitation_process = wpas_invitation_process;
3191 p2p.invitation_received = wpas_invitation_received;
3192 p2p.invitation_result = wpas_invitation_result;
3193 p2p.get_noa = wpas_get_noa;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003194 p2p.go_connected = wpas_go_connected;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003195
3196 os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003197 os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003198 p2p.dev_name = wpa_s->conf->device_name;
3199 p2p.manufacturer = wpa_s->conf->manufacturer;
3200 p2p.model_name = wpa_s->conf->model_name;
3201 p2p.model_number = wpa_s->conf->model_number;
3202 p2p.serial_number = wpa_s->conf->serial_number;
3203 if (wpa_s->wps) {
3204 os_memcpy(p2p.uuid, wpa_s->wps->uuid, 16);
3205 p2p.config_methods = wpa_s->wps->config_methods;
3206 }
3207
3208 if (wpa_s->conf->p2p_listen_reg_class &&
3209 wpa_s->conf->p2p_listen_channel) {
3210 p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
3211 p2p.channel = wpa_s->conf->p2p_listen_channel;
3212 } else {
3213 p2p.reg_class = 81;
3214 /*
3215 * Pick one of the social channels randomly as the listen
3216 * channel.
3217 */
3218 os_get_random((u8 *) &r, sizeof(r));
3219 p2p.channel = 1 + (r % 3) * 5;
3220 }
3221 wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
3222
3223 if (wpa_s->conf->p2p_oper_reg_class &&
3224 wpa_s->conf->p2p_oper_channel) {
3225 p2p.op_reg_class = wpa_s->conf->p2p_oper_reg_class;
3226 p2p.op_channel = wpa_s->conf->p2p_oper_channel;
3227 p2p.cfg_op_channel = 1;
3228 wpa_printf(MSG_DEBUG, "P2P: Configured operating channel: "
3229 "%d:%d", p2p.op_reg_class, p2p.op_channel);
3230
3231 } else {
3232 p2p.op_reg_class = 81;
3233 /*
3234 * Use random operation channel from (1, 6, 11) if no other
3235 * preference is indicated.
3236 */
3237 os_get_random((u8 *) &r, sizeof(r));
3238 p2p.op_channel = 1 + (r % 3) * 5;
3239 p2p.cfg_op_channel = 0;
3240 wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
3241 "%d:%d", p2p.op_reg_class, p2p.op_channel);
3242 }
Dmitry Shmidt44c95782013-05-17 09:51:35 -07003243
3244 if (wpa_s->conf->p2p_pref_chan && wpa_s->conf->num_p2p_pref_chan) {
3245 p2p.pref_chan = wpa_s->conf->p2p_pref_chan;
3246 p2p.num_pref_chan = wpa_s->conf->num_p2p_pref_chan;
3247 }
3248
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003249 if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
3250 os_memcpy(p2p.country, wpa_s->conf->country, 2);
3251 p2p.country[2] = 0x04;
3252 } else
3253 os_memcpy(p2p.country, "XX\x04", 3);
3254
3255 if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
3256 wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
3257 "channel list");
3258 return -1;
3259 }
3260
3261 os_memcpy(p2p.pri_dev_type, wpa_s->conf->device_type,
3262 WPS_DEV_TYPE_LEN);
3263
3264 p2p.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
3265 os_memcpy(p2p.sec_dev_type, wpa_s->conf->sec_device_type,
3266 p2p.num_sec_dev_types * WPS_DEV_TYPE_LEN);
3267
3268 p2p.concurrent_operations = !!(wpa_s->drv_flags &
3269 WPA_DRIVER_FLAGS_P2P_CONCURRENT);
3270
3271 p2p.max_peers = 100;
3272
3273 if (wpa_s->conf->p2p_ssid_postfix) {
3274 p2p.ssid_postfix_len =
3275 os_strlen(wpa_s->conf->p2p_ssid_postfix);
3276 if (p2p.ssid_postfix_len > sizeof(p2p.ssid_postfix))
3277 p2p.ssid_postfix_len = sizeof(p2p.ssid_postfix);
3278 os_memcpy(p2p.ssid_postfix, wpa_s->conf->p2p_ssid_postfix,
3279 p2p.ssid_postfix_len);
3280 }
3281
3282 p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
3283
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003284 p2p.max_listen = wpa_s->max_remain_on_chan;
3285
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003286 global->p2p = p2p_init(&p2p);
3287 if (global->p2p == NULL)
3288 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003289 global->p2p_init_wpa_s = wpa_s;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003290
3291 for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
3292 if (wpa_s->conf->wps_vendor_ext[i] == NULL)
3293 continue;
3294 p2p_add_wps_vendor_extension(
3295 global->p2p, wpa_s->conf->wps_vendor_ext[i]);
3296 }
3297
3298 return 0;
3299}
3300
3301
3302/**
3303 * wpas_p2p_deinit - Deinitialize per-interface P2P data
3304 * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
3305 *
3306 * This function deinitialize per-interface P2P data.
3307 */
3308void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
3309{
3310 if (wpa_s->driver && wpa_s->drv_priv)
3311 wpa_drv_probe_req_report(wpa_s, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003312
3313 if (wpa_s->go_params) {
3314 /* Clear any stored provisioning info */
3315 p2p_clear_provisioning_info(
3316 wpa_s->global->p2p,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003317 wpa_s->go_params->peer_device_addr);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003318 }
3319
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003320 os_free(wpa_s->go_params);
3321 wpa_s->go_params = NULL;
Dmitry Shmidt1cf45732013-04-29 17:36:45 -07003322#ifdef ANDROID_P2P
3323 eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
3324#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003325 eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
3326 eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
3327 wpa_s->p2p_long_listen = 0;
3328 eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
3329 eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
3330 wpas_p2p_remove_pending_group_interface(wpa_s);
3331
3332 /* TODO: remove group interface from the driver if this wpa_s instance
3333 * is on top of a P2P group interface */
3334}
3335
3336
3337/**
3338 * wpas_p2p_deinit_global - Deinitialize global P2P module
3339 * @global: Pointer to global data from wpa_supplicant_init()
3340 *
3341 * This function deinitializes the global (per device) P2P module.
3342 */
3343void wpas_p2p_deinit_global(struct wpa_global *global)
3344{
3345 struct wpa_supplicant *wpa_s, *tmp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003346
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003347 wpa_s = global->ifaces;
3348 if (wpa_s)
3349 wpas_p2p_service_flush(wpa_s);
3350
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003351 if (global->p2p == NULL)
3352 return;
3353
3354 /* Remove remaining P2P group interfaces */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003355 while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
3356 wpa_s = wpa_s->next;
3357 while (wpa_s) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003358 tmp = global->ifaces;
3359 while (tmp &&
3360 (tmp == wpa_s ||
3361 tmp->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)) {
3362 tmp = tmp->next;
3363 }
3364 if (tmp == NULL)
3365 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003366 /* Disconnect from the P2P group and deinit the interface */
3367 wpas_p2p_disconnect(tmp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003368 }
3369
3370 /*
3371 * Deinit GO data on any possibly remaining interface (if main
3372 * interface is used as GO).
3373 */
3374 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
3375 if (wpa_s->ap_iface)
3376 wpas_p2p_group_deinit(wpa_s);
3377 }
3378
3379 p2p_deinit(global->p2p);
3380 global->p2p = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003381 global->p2p_init_wpa_s = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003382}
3383
3384
3385static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
3386{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003387 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
3388 wpa_s->conf->p2p_no_group_iface)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003389 return 0; /* separate interface disabled per configuration */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003390 if (wpa_s->drv_flags &
3391 (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
3392 WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P))
3393 return 1; /* P2P group requires a new interface in every case
3394 */
3395 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CONCURRENT))
3396 return 0; /* driver does not support concurrent operations */
3397 if (wpa_s->global->ifaces->next)
3398 return 1; /* more that one interface already in use */
3399 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3400 return 1; /* this interface is already in use */
3401 return 0;
3402}
3403
3404
3405static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
3406 const u8 *peer_addr,
3407 enum p2p_wps_method wps_method,
3408 int go_intent, const u8 *own_interface_addr,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003409 unsigned int force_freq, int persistent_group,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003410 struct wpa_ssid *ssid, unsigned int pref_freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003411{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003412 if (persistent_group && wpa_s->conf->persistent_reconnect)
3413 persistent_group = 2;
3414
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003415 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
3416 return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method,
3417 go_intent, own_interface_addr,
3418 force_freq, persistent_group);
3419 }
3420
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003421 /*
3422 * Increase GO config timeout if HT40 is used since it takes some time
3423 * to scan channels for coex purposes before the BSS can be started.
3424 */
3425 p2p_set_config_timeout(wpa_s->global->p2p,
3426 wpa_s->p2p_go_ht40 ? 255 : 100, 20);
3427
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003428 return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method,
3429 go_intent, own_interface_addr, force_freq,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003430 persistent_group, ssid ? ssid->ssid : NULL,
3431 ssid ? ssid->ssid_len : 0,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003432 wpa_s->p2p_pd_before_go_neg, pref_freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003433}
3434
3435
3436static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
3437 const u8 *peer_addr,
3438 enum p2p_wps_method wps_method,
3439 int go_intent, const u8 *own_interface_addr,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003440 unsigned int force_freq, int persistent_group,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003441 struct wpa_ssid *ssid, unsigned int pref_freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003442{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003443 if (persistent_group && wpa_s->conf->persistent_reconnect)
3444 persistent_group = 2;
3445
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003446 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
3447 return -1;
3448
3449 return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
3450 go_intent, own_interface_addr, force_freq,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003451 persistent_group, ssid ? ssid->ssid : NULL,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003452 ssid ? ssid->ssid_len : 0, pref_freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003453}
3454
3455
3456static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
3457{
3458 wpa_s->p2p_join_scan_count++;
3459 wpa_printf(MSG_DEBUG, "P2P: Join scan attempt %d",
3460 wpa_s->p2p_join_scan_count);
3461 if (wpa_s->p2p_join_scan_count > P2P_MAX_JOIN_SCAN_ATTEMPTS) {
3462 wpa_printf(MSG_DEBUG, "P2P: Failed to find GO " MACSTR
3463 " for join operationg - stop join attempt",
3464 MAC2STR(wpa_s->pending_join_iface_addr));
3465 eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003466 if (wpa_s->p2p_auto_pd) {
3467 wpa_s->p2p_auto_pd = 0;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07003468 wpa_msg_global(wpa_s, MSG_INFO,
3469 P2P_EVENT_PROV_DISC_FAILURE
3470 " p2p_dev_addr=" MACSTR " status=N/A",
3471 MAC2STR(wpa_s->pending_join_dev_addr));
Dmitry Shmidt04949592012-07-19 12:16:46 -07003472 return;
3473 }
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07003474 wpa_msg_global(wpa_s->parent, MSG_INFO,
3475 P2P_EVENT_GROUP_FORMATION_FAILURE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003476 }
3477}
3478
3479
Dmitry Shmidt04949592012-07-19 12:16:46 -07003480static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
3481{
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003482 int *freqs, res, num, i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003483
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003484 if (wpas_p2p_num_unused_channels(wpa_s) > 0) {
3485 /* Multiple channels are supported and not all are in use */
Dmitry Shmidt04949592012-07-19 12:16:46 -07003486 return 0;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003487 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003488
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003489 freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
3490 if (!freqs)
3491 return 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003492
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003493 num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
3494 wpa_s->num_multichan_concurrent);
3495 if (num < 0) {
3496 res = 1;
3497 goto exit_free;
3498 }
3499
3500 for (i = 0; i < num; i++) {
3501 if (freqs[i] == freq) {
3502 wpa_printf(MSG_DEBUG, "P2P: Frequency %d MHz in use by another virtual interface and can be used",
3503 freq);
3504 res = 0;
3505 goto exit_free;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003506 }
3507 }
3508
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003509 res = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003510
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003511exit_free:
3512 os_free(freqs);
3513 return res;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003514}
3515
3516
3517static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s,
3518 const u8 *peer_dev_addr)
3519{
3520 struct wpa_bss *bss;
3521 int updated;
3522
3523 bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr);
3524 if (bss == NULL)
3525 return -1;
3526 if (bss->last_update_idx < wpa_s->bss_update_idx) {
3527 wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the "
3528 "last scan");
3529 return 0;
3530 }
3531
3532 updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update);
3533 wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at "
3534 "%ld.%06ld (%supdated in last scan)",
3535 bss->last_update.sec, bss->last_update.usec,
3536 updated ? "": "not ");
3537
3538 return updated;
3539}
3540
3541
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003542static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
3543 struct wpa_scan_results *scan_res)
3544{
3545 struct wpa_bss *bss;
3546 int freq;
3547 u8 iface_addr[ETH_ALEN];
Dmitry Shmidt04949592012-07-19 12:16:46 -07003548
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003549 eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
3550
3551 if (wpa_s->global->p2p_disabled)
3552 return;
3553
Dmitry Shmidt04949592012-07-19 12:16:46 -07003554 wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for %sjoin",
3555 scan_res ? (int) scan_res->num : -1,
3556 wpa_s->p2p_auto_join ? "auto_" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003557
3558 if (scan_res)
3559 wpas_p2p_scan_res_handler(wpa_s, scan_res);
3560
Dmitry Shmidt04949592012-07-19 12:16:46 -07003561 if (wpa_s->p2p_auto_pd) {
3562 int join = wpas_p2p_peer_go(wpa_s,
3563 wpa_s->pending_join_dev_addr);
3564 if (join == 0 &&
3565 wpa_s->auto_pd_scan_retry < P2P_AUTO_PD_SCAN_ATTEMPTS) {
3566 wpa_s->auto_pd_scan_retry++;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07003567 bss = wpa_bss_get_bssid_latest(
3568 wpa_s, wpa_s->pending_join_dev_addr);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003569 if (bss) {
3570 freq = bss->freq;
3571 wpa_printf(MSG_DEBUG, "P2P: Scan retry %d for "
3572 "the peer " MACSTR " at %d MHz",
3573 wpa_s->auto_pd_scan_retry,
3574 MAC2STR(wpa_s->
3575 pending_join_dev_addr),
3576 freq);
3577 wpas_p2p_join_scan_req(wpa_s, freq);
3578 return;
3579 }
3580 }
3581
3582 if (join < 0)
3583 join = 0;
3584
3585 wpa_s->p2p_auto_pd = 0;
3586 wpa_s->pending_pd_use = join ? AUTO_PD_JOIN : AUTO_PD_GO_NEG;
3587 wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d",
3588 MAC2STR(wpa_s->pending_join_dev_addr), join);
3589 if (p2p_prov_disc_req(wpa_s->global->p2p,
3590 wpa_s->pending_join_dev_addr,
3591 wpa_s->pending_pd_config_methods, join,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003592 0, wpa_s->user_initiated_pd) < 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07003593 wpa_s->p2p_auto_pd = 0;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07003594 wpa_msg_global(wpa_s, MSG_INFO,
3595 P2P_EVENT_PROV_DISC_FAILURE
3596 " p2p_dev_addr=" MACSTR " status=N/A",
3597 MAC2STR(wpa_s->pending_join_dev_addr));
Dmitry Shmidt04949592012-07-19 12:16:46 -07003598 }
3599 return;
3600 }
3601
3602 if (wpa_s->p2p_auto_join) {
3603 int join = wpas_p2p_peer_go(wpa_s,
3604 wpa_s->pending_join_dev_addr);
3605 if (join < 0) {
3606 wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
3607 "running a GO -> use GO Negotiation");
3608 wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
3609 wpa_s->p2p_pin, wpa_s->p2p_wps_method,
3610 wpa_s->p2p_persistent_group, 0, 0, 0,
3611 wpa_s->p2p_go_intent,
3612 wpa_s->p2p_connect_freq,
3613 wpa_s->p2p_persistent_id,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003614 wpa_s->p2p_pd_before_go_neg,
3615 wpa_s->p2p_go_ht40);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003616 return;
3617 }
3618
3619 wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> "
3620 "try to join the group", join ? "" :
3621 " in older scan");
3622 if (!join)
3623 wpa_s->p2p_fallback_to_go_neg = 1;
3624 }
3625
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003626 freq = p2p_get_oper_freq(wpa_s->global->p2p,
3627 wpa_s->pending_join_iface_addr);
3628 if (freq < 0 &&
3629 p2p_get_interface_addr(wpa_s->global->p2p,
3630 wpa_s->pending_join_dev_addr,
3631 iface_addr) == 0 &&
3632 os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0)
3633 {
3634 wpa_printf(MSG_DEBUG, "P2P: Overwrite pending interface "
3635 "address for join from " MACSTR " to " MACSTR
3636 " based on newly discovered P2P peer entry",
3637 MAC2STR(wpa_s->pending_join_iface_addr),
3638 MAC2STR(iface_addr));
3639 os_memcpy(wpa_s->pending_join_iface_addr, iface_addr,
3640 ETH_ALEN);
3641
3642 freq = p2p_get_oper_freq(wpa_s->global->p2p,
3643 wpa_s->pending_join_iface_addr);
3644 }
3645 if (freq >= 0) {
3646 wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
3647 "from P2P peer table: %d MHz", freq);
3648 }
Dmitry Shmidt444d5672013-04-01 13:08:44 -07003649 bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003650 if (bss) {
3651 freq = bss->freq;
3652 wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
3653 "from BSS table: %d MHz", freq);
3654 }
3655 if (freq > 0) {
3656 u16 method;
3657
Dmitry Shmidt04949592012-07-19 12:16:46 -07003658 if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07003659 wpa_msg_global(wpa_s->parent, MSG_INFO,
3660 P2P_EVENT_GROUP_FORMATION_FAILURE
3661 "reason=FREQ_CONFLICT");
Dmitry Shmidt04949592012-07-19 12:16:46 -07003662 return;
3663 }
3664
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003665 wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request "
3666 "prior to joining an existing group (GO " MACSTR
3667 " freq=%u MHz)",
3668 MAC2STR(wpa_s->pending_join_dev_addr), freq);
3669 wpa_s->pending_pd_before_join = 1;
3670
3671 switch (wpa_s->pending_join_wps_method) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003672 case WPS_PIN_DISPLAY:
3673 method = WPS_CONFIG_KEYPAD;
3674 break;
3675 case WPS_PIN_KEYPAD:
3676 method = WPS_CONFIG_DISPLAY;
3677 break;
3678 case WPS_PBC:
3679 method = WPS_CONFIG_PUSHBUTTON;
3680 break;
3681 default:
3682 method = 0;
3683 break;
3684 }
3685
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003686 if ((p2p_get_provisioning_info(wpa_s->global->p2p,
3687 wpa_s->pending_join_dev_addr) ==
3688 method)) {
3689 /*
3690 * We have already performed provision discovery for
3691 * joining the group. Proceed directly to join
3692 * operation without duplicated provision discovery. */
3693 wpa_printf(MSG_DEBUG, "P2P: Provision discovery "
3694 "with " MACSTR " already done - proceed to "
3695 "join",
3696 MAC2STR(wpa_s->pending_join_dev_addr));
3697 wpa_s->pending_pd_before_join = 0;
3698 goto start;
3699 }
3700
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003701 if (p2p_prov_disc_req(wpa_s->global->p2p,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003702 wpa_s->pending_join_dev_addr, method, 1,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003703 freq, wpa_s->user_initiated_pd) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003704 wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
3705 "Discovery Request before joining an "
3706 "existing group");
3707 wpa_s->pending_pd_before_join = 0;
3708 goto start;
3709 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003710 return;
3711 }
3712
3713 wpa_printf(MSG_DEBUG, "P2P: Failed to find BSS/GO - try again later");
3714 eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
3715 eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
3716 wpas_p2p_check_join_scan_limit(wpa_s);
3717 return;
3718
3719start:
3720 /* Start join operation immediately */
3721 wpas_p2p_join_start(wpa_s);
3722}
3723
3724
Dmitry Shmidt04949592012-07-19 12:16:46 -07003725static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003726{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003727 int ret;
3728 struct wpa_driver_scan_params params;
3729 struct wpabuf *wps_ie, *ies;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003730 size_t ielen;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003731 int freqs[2] = { 0, 0 };
Dmitry Shmidtad266fb2012-08-24 17:03:35 -07003732#ifdef ANDROID_P2P
3733 int oper_freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003734
Dmitry Shmidtad266fb2012-08-24 17:03:35 -07003735 /* If freq is not provided, check the operating freq of the GO and do a
3736 * a directed scan to save time
3737 */
3738 if(!freq) {
3739 freq = (oper_freq = p2p_get_oper_freq(wpa_s->global->p2p,
3740 wpa_s->pending_join_iface_addr) == -1) ? 0 : oper_freq;
3741 }
3742#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003743 os_memset(&params, 0, sizeof(params));
3744
3745 /* P2P Wildcard SSID */
3746 params.num_ssids = 1;
3747 params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
3748 params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
3749
3750 wpa_s->wps->dev.p2p = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003751 wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
3752 wpa_s->wps->uuid, WPS_REQ_ENROLLEE, 0,
3753 NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003754 if (wps_ie == NULL) {
3755 wpas_p2p_scan_res_join(wpa_s, NULL);
3756 return;
3757 }
3758
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003759 ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
3760 ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003761 if (ies == NULL) {
3762 wpabuf_free(wps_ie);
3763 wpas_p2p_scan_res_join(wpa_s, NULL);
3764 return;
3765 }
3766 wpabuf_put_buf(ies, wps_ie);
3767 wpabuf_free(wps_ie);
3768
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003769 p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003770
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003771 params.p2p_probe = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003772 params.extra_ies = wpabuf_head(ies);
3773 params.extra_ies_len = wpabuf_len(ies);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003774 if (freq > 0) {
3775 freqs[0] = freq;
3776 params.freqs = freqs;
3777 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003778
3779 /*
3780 * Run a scan to update BSS table and start Provision Discovery once
3781 * the new scan results become available.
3782 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003783 ret = wpa_drv_scan(wpa_s, &params);
Dmitry Shmidt444d5672013-04-01 13:08:44 -07003784 if (!ret) {
3785 os_get_time(&wpa_s->scan_trigger_time);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003786 wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07003787 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003788
3789 wpabuf_free(ies);
3790
3791 if (ret) {
3792 wpa_printf(MSG_DEBUG, "P2P: Failed to start scan for join - "
3793 "try again later");
3794 eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
3795 eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
3796 wpas_p2p_check_join_scan_limit(wpa_s);
3797 }
3798}
3799
3800
Dmitry Shmidt04949592012-07-19 12:16:46 -07003801static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
3802{
3803 struct wpa_supplicant *wpa_s = eloop_ctx;
3804 wpas_p2p_join_scan_req(wpa_s, 0);
3805}
3806
3807
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003808static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003809 const u8 *dev_addr, enum p2p_wps_method wps_method,
3810 int auto_join)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003811{
3812 wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
Dmitry Shmidt04949592012-07-19 12:16:46 -07003813 MACSTR " dev " MACSTR ")%s",
3814 MAC2STR(iface_addr), MAC2STR(dev_addr),
3815 auto_join ? " (auto_join)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003816
Dmitry Shmidt04949592012-07-19 12:16:46 -07003817 wpa_s->p2p_auto_pd = 0;
3818 wpa_s->p2p_auto_join = !!auto_join;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003819 os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN);
3820 os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN);
3821 wpa_s->pending_join_wps_method = wps_method;
3822
3823 /* Make sure we are not running find during connection establishment */
3824 wpas_p2p_stop_find(wpa_s);
3825
3826 wpa_s->p2p_join_scan_count = 0;
3827 wpas_p2p_join_scan(wpa_s, NULL);
3828 return 0;
3829}
3830
3831
3832static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
3833{
3834 struct wpa_supplicant *group;
3835 struct p2p_go_neg_results res;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003836 struct wpa_bss *bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003837
3838 group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
3839 if (group == NULL)
3840 return -1;
3841 if (group != wpa_s) {
3842 os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
3843 sizeof(group->p2p_pin));
3844 group->p2p_wps_method = wpa_s->p2p_wps_method;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003845 } else {
3846 /*
3847 * Need to mark the current interface for p2p_group_formation
3848 * when a separate group interface is not used. This is needed
3849 * to allow p2p_cancel stop a pending p2p_connect-join.
3850 * wpas_p2p_init_group_interface() addresses this for the case
3851 * where a separate group interface is used.
3852 */
3853 wpa_s->global->p2p_group_formation = wpa_s;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003854 }
3855
3856 group->p2p_in_provisioning = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003857 group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003858
3859 os_memset(&res, 0, sizeof(res));
3860 os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
3861 ETH_ALEN);
3862 res.wps_method = wpa_s->pending_join_wps_method;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07003863 bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003864 if (bss) {
3865 res.freq = bss->freq;
3866 res.ssid_len = bss->ssid_len;
3867 os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
3868 }
3869
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003870 if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
3871 wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel prior to "
3872 "starting client");
3873 wpa_drv_cancel_remain_on_channel(wpa_s);
3874 wpa_s->off_channel_freq = 0;
3875 wpa_s->roc_waiting_drv_freq = 0;
3876 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003877 wpas_start_wps_enrollee(group, &res);
3878
3879 /*
3880 * Allow a longer timeout for join-a-running-group than normal 15
3881 * second group formation timeout since the GO may not have authorized
3882 * our connection yet.
3883 */
3884 eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
3885 eloop_register_timeout(60, 0, wpas_p2p_group_formation_timeout,
3886 wpa_s, NULL);
3887
3888 return 0;
3889}
3890
3891
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08003892static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003893 int *force_freq, int *pref_freq)
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08003894{
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003895 int *freqs, res;
3896 unsigned int freq_in_use = 0, num, i;
3897
3898 freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
3899 if (!freqs)
3900 return -1;
3901
3902 num = get_shared_radio_freqs(wpa_s, freqs,
3903 wpa_s->num_multichan_concurrent);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07003904 wpa_printf(MSG_DEBUG,
3905 "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u",
3906 freq, wpa_s->num_multichan_concurrent, num);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003907
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08003908 if (freq > 0) {
3909 if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
3910 wpa_printf(MSG_DEBUG, "P2P: The forced channel "
3911 "(%u MHz) is not supported for P2P uses",
3912 freq);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003913 res = -3;
3914 goto exit_free;
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08003915 }
3916
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003917 for (i = 0; i < num; i++) {
3918 if (freqs[i] == freq)
3919 freq_in_use = 1;
3920 }
3921
3922 if (num == wpa_s->num_multichan_concurrent && !freq_in_use) {
3923 wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz as there are no available channels",
3924 freq);
3925 res = -2;
3926 goto exit_free;
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08003927 }
3928 wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
3929 "requested channel (%u MHz)", freq);
3930 *force_freq = freq;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003931 goto exit_ok;
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08003932 }
3933
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003934 for (i = 0; i < num; i++) {
3935 if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
3936 continue;
3937
3938 wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
3939 *force_freq);
3940 *force_freq = freqs[i];
3941
3942 if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) {
3943 wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency we are already using");
3944 *pref_freq = *force_freq;
3945 }
3946 break;
3947 }
3948
3949 if (i == num) {
3950 if (num < wpa_s->num_multichan_concurrent) {
3951 wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel");
3952 *force_freq = 0;
3953 } else {
3954 wpa_printf(MSG_DEBUG, "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group");
3955 res = -2;
3956 goto exit_free;
3957 }
3958 }
3959
3960exit_ok:
3961 res = 0;
3962exit_free:
3963 os_free(freqs);
3964 return res;
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08003965}
3966
3967
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003968/**
3969 * wpas_p2p_connect - Request P2P Group Formation to be started
3970 * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
3971 * @peer_addr: Address of the peer P2P Device
3972 * @pin: PIN to use during provisioning or %NULL to indicate PBC mode
3973 * @persistent_group: Whether to create a persistent group
Dmitry Shmidt04949592012-07-19 12:16:46 -07003974 * @auto_join: Whether to select join vs. GO Negotiation automatically
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003975 * @join: Whether to join an existing group (as a client) instead of starting
3976 * Group Owner negotiation; @peer_addr is BSSID in that case
3977 * @auth: Whether to only authorize the connection instead of doing that and
3978 * initiating Group Owner negotiation
3979 * @go_intent: GO Intent or -1 to use default
3980 * @freq: Frequency for the group or 0 for auto-selection
Dmitry Shmidt04949592012-07-19 12:16:46 -07003981 * @persistent_id: Persistent group credentials to use for forcing GO
3982 * parameters or -1 to generate new values (SSID/passphrase)
3983 * @pd: Whether to send Provision Discovery prior to GO Negotiation as an
3984 * interoperability workaround when initiating group formation
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003985 * @ht40: Start GO with 40 MHz channel width
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003986 * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
3987 * failure, -2 on failure due to channel not currently available,
3988 * -3 if forced channel is not supported
3989 */
3990int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
3991 const char *pin, enum p2p_wps_method wps_method,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003992 int persistent_group, int auto_join, int join, int auth,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003993 int go_intent, int freq, int persistent_id, int pd,
3994 int ht40)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003995{
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003996 int force_freq = 0, pref_freq = 0;
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08003997 int ret = 0, res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003998 enum wpa_driver_if_type iftype;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003999 const u8 *if_addr;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004000 struct wpa_ssid *ssid = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004001
4002 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
4003 return -1;
4004
Dmitry Shmidt04949592012-07-19 12:16:46 -07004005 if (persistent_id >= 0) {
4006 ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
4007 if (ssid == NULL || ssid->disabled != 2 ||
4008 ssid->mode != WPAS_MODE_P2P_GO)
4009 return -1;
4010 }
4011
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004012 if (go_intent < 0)
4013 go_intent = wpa_s->conf->p2p_go_intent;
4014
4015 if (!auth)
4016 wpa_s->p2p_long_listen = 0;
4017
4018 wpa_s->p2p_wps_method = wps_method;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004019 wpa_s->p2p_persistent_group = !!persistent_group;
4020 wpa_s->p2p_persistent_id = persistent_id;
4021 wpa_s->p2p_go_intent = go_intent;
4022 wpa_s->p2p_connect_freq = freq;
4023 wpa_s->p2p_fallback_to_go_neg = 0;
4024 wpa_s->p2p_pd_before_go_neg = !!pd;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004025 wpa_s->p2p_go_ht40 = !!ht40;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004026
4027 if (pin)
4028 os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
4029 else if (wps_method == WPS_PIN_DISPLAY) {
4030 ret = wps_generate_pin();
4031 os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin), "%08d",
4032 ret);
4033 wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
4034 wpa_s->p2p_pin);
4035 } else
4036 wpa_s->p2p_pin[0] = '\0';
4037
Dmitry Shmidt04949592012-07-19 12:16:46 -07004038 if (join || auto_join) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004039 u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
4040 if (auth) {
4041 wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
4042 "connect a running group from " MACSTR,
4043 MAC2STR(peer_addr));
4044 os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
4045 return ret;
4046 }
4047 os_memcpy(dev_addr, peer_addr, ETH_ALEN);
4048 if (p2p_get_interface_addr(wpa_s->global->p2p, peer_addr,
4049 iface_addr) < 0) {
4050 os_memcpy(iface_addr, peer_addr, ETH_ALEN);
4051 p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
4052 dev_addr);
4053 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004054 if (auto_join) {
4055 os_get_time(&wpa_s->p2p_auto_started);
4056 wpa_printf(MSG_DEBUG, "P2P: Auto join started at "
4057 "%ld.%06ld",
4058 wpa_s->p2p_auto_started.sec,
4059 wpa_s->p2p_auto_started.usec);
4060 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004061 wpa_s->user_initiated_pd = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004062 if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
4063 auto_join) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004064 return -1;
4065 return ret;
4066 }
4067
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07004068 res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004069 if (res)
4070 return res;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07004071 wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004072
4073 wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
4074
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004075 if (wpa_s->create_p2p_iface) {
4076 /* Prepare to add a new interface for the group */
4077 iftype = WPA_IF_P2P_GROUP;
4078 if (go_intent == 15)
4079 iftype = WPA_IF_P2P_GO;
4080 if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
4081 wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
4082 "interface for the group");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004083 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004084 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004085
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004086 if_addr = wpa_s->pending_interface_addr;
4087 } else
4088 if_addr = wpa_s->own_addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004089
4090 if (auth) {
4091 if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004092 go_intent, if_addr,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004093 force_freq, persistent_group, ssid,
4094 pref_freq) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004095 return -1;
4096 return ret;
4097 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004098
4099 if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
4100 go_intent, if_addr, force_freq,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004101 persistent_group, ssid, pref_freq) < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004102 if (wpa_s->create_p2p_iface)
4103 wpas_p2p_remove_pending_group_interface(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004104 return -1;
4105 }
4106 return ret;
4107}
4108
4109
4110/**
4111 * wpas_p2p_remain_on_channel_cb - Indication of remain-on-channel start
4112 * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
4113 * @freq: Frequency of the channel in MHz
4114 * @duration: Duration of the stay on the channel in milliseconds
4115 *
4116 * This callback is called when the driver indicates that it has started the
4117 * requested remain-on-channel duration.
4118 */
4119void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
4120 unsigned int freq, unsigned int duration)
4121{
4122 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
4123 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004124 if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
4125 p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
4126 wpa_s->pending_listen_duration);
4127 wpa_s->pending_listen_freq = 0;
4128 }
4129}
4130
4131
4132static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s,
4133 unsigned int timeout)
4134{
4135 /* Limit maximum Listen state time based on driver limitation. */
4136 if (timeout > wpa_s->max_remain_on_chan)
4137 timeout = wpa_s->max_remain_on_chan;
4138
4139 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
4140 return wpa_drv_p2p_listen(wpa_s, timeout);
4141
4142 return p2p_listen(wpa_s->global->p2p, timeout);
4143}
4144
4145
4146/**
4147 * wpas_p2p_cancel_remain_on_channel_cb - Remain-on-channel timeout
4148 * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
4149 * @freq: Frequency of the channel in MHz
4150 *
4151 * This callback is called when the driver indicates that a remain-on-channel
4152 * operation has been completed, i.e., the duration on the requested channel
4153 * has timed out.
4154 */
4155void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
4156 unsigned int freq)
4157{
4158 wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
4159 "(p2p_long_listen=%d ms pending_action_tx=%p)",
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004160 wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004161 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
4162 return;
4163 if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
4164 return; /* P2P module started a new operation */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004165 if (offchannel_pending_action_tx(wpa_s))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004166 return;
4167 if (wpa_s->p2p_long_listen > 0)
4168 wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
4169 if (wpa_s->p2p_long_listen > 0) {
4170 wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
4171 wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
4172 }
4173}
4174
4175
4176/**
4177 * wpas_p2p_group_remove - Remove a P2P group
4178 * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
4179 * @ifname: Network interface name of the group interface or "*" to remove all
4180 * groups
4181 * Returns: 0 on success, -1 on failure
4182 *
4183 * This function is used to remove a P2P group. This can be used to disconnect
4184 * from a group in which the local end is a P2P Client or to end a P2P Group in
4185 * case the local end is the Group Owner. If a virtual network interface was
4186 * created for this group, that interface will be removed. Otherwise, only the
4187 * configured P2P group network will be removed from the interface.
4188 */
4189int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
4190{
4191 struct wpa_global *global = wpa_s->global;
4192
4193 if (os_strcmp(ifname, "*") == 0) {
4194 struct wpa_supplicant *prev;
4195 wpa_s = global->ifaces;
4196 while (wpa_s) {
4197 prev = wpa_s;
4198 wpa_s = wpa_s->next;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07004199 if (prev->p2p_group_interface !=
4200 NOT_P2P_GROUP_INTERFACE ||
4201 (prev->current_ssid &&
4202 prev->current_ssid->p2p_group))
4203 wpas_p2p_disconnect(prev);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004204 }
4205 return 0;
4206 }
4207
4208 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
4209 if (os_strcmp(wpa_s->ifname, ifname) == 0)
4210 break;
4211 }
4212
4213 return wpas_p2p_disconnect(wpa_s);
4214}
4215
4216
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004217static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
4218{
4219 unsigned int r;
4220
4221 if (freq == 2) {
4222 wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
4223 "band");
4224 if (wpa_s->best_24_freq > 0 &&
4225 p2p_supported_freq(wpa_s->global->p2p,
4226 wpa_s->best_24_freq)) {
4227 freq = wpa_s->best_24_freq;
4228 wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
4229 "channel: %d MHz", freq);
4230 } else {
4231 os_get_random((u8 *) &r, sizeof(r));
4232 freq = 2412 + (r % 3) * 25;
4233 wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
4234 "channel: %d MHz", freq);
4235 }
4236 }
4237
4238 if (freq == 5) {
4239 wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
4240 "band");
4241 if (wpa_s->best_5_freq > 0 &&
4242 p2p_supported_freq(wpa_s->global->p2p,
4243 wpa_s->best_5_freq)) {
4244 freq = wpa_s->best_5_freq;
4245 wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
4246 "channel: %d MHz", freq);
4247 } else {
4248 os_get_random((u8 *) &r, sizeof(r));
4249 freq = 5180 + (r % 4) * 20;
4250 if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
4251 wpa_printf(MSG_DEBUG, "P2P: Could not select "
4252 "5 GHz channel for P2P group");
4253 return -1;
4254 }
4255 wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
4256 "channel: %d MHz", freq);
4257 }
4258 }
4259
4260 if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
4261 wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
4262 "(%u MHz) is not supported for P2P uses",
4263 freq);
4264 return -1;
4265 }
4266
4267 return freq;
4268}
4269
4270
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004271static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
4272 struct p2p_go_neg_results *params,
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004273 int freq, int ht40,
4274 const struct p2p_channels *channels)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004275{
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07004276 int res, *freqs;
Dmitry Shmidt44c95782013-05-17 09:51:35 -07004277 unsigned int pref_freq;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07004278 unsigned int num, i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004279
4280 os_memset(params, 0, sizeof(*params));
4281 params->role_go = 1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004282 params->ht40 = ht40;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004283 if (freq) {
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004284 if (!freq_included(channels, freq)) {
4285 wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
4286 "accepted", freq);
4287 return -1;
4288 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004289 wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
4290 "frequency %d MHz", freq);
4291 params->freq = freq;
4292 } else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
4293 wpa_s->conf->p2p_oper_channel >= 1 &&
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004294 wpa_s->conf->p2p_oper_channel <= 11 &&
4295 freq_included(channels,
4296 2407 + 5 * wpa_s->conf->p2p_oper_channel)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004297 params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel;
4298 wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
4299 "frequency %d MHz", params->freq);
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004300 } else if ((wpa_s->conf->p2p_oper_reg_class == 115 ||
4301 wpa_s->conf->p2p_oper_reg_class == 116 ||
4302 wpa_s->conf->p2p_oper_reg_class == 117 ||
4303 wpa_s->conf->p2p_oper_reg_class == 124 ||
4304 wpa_s->conf->p2p_oper_reg_class == 126 ||
4305 wpa_s->conf->p2p_oper_reg_class == 127) &&
4306 freq_included(channels,
4307 5000 + 5 * wpa_s->conf->p2p_oper_channel)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004308 params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
4309 wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
4310 "frequency %d MHz", params->freq);
4311 } else if (wpa_s->conf->p2p_oper_channel == 0 &&
4312 wpa_s->best_overall_freq > 0 &&
4313 p2p_supported_freq(wpa_s->global->p2p,
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004314 wpa_s->best_overall_freq) &&
4315 freq_included(channels, wpa_s->best_overall_freq)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004316 params->freq = wpa_s->best_overall_freq;
4317 wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
4318 "channel %d MHz", params->freq);
4319 } else if (wpa_s->conf->p2p_oper_channel == 0 &&
4320 wpa_s->best_24_freq > 0 &&
4321 p2p_supported_freq(wpa_s->global->p2p,
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004322 wpa_s->best_24_freq) &&
4323 freq_included(channels, wpa_s->best_24_freq)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004324 params->freq = wpa_s->best_24_freq;
4325 wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
4326 "channel %d MHz", params->freq);
4327 } else if (wpa_s->conf->p2p_oper_channel == 0 &&
4328 wpa_s->best_5_freq > 0 &&
4329 p2p_supported_freq(wpa_s->global->p2p,
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004330 wpa_s->best_5_freq) &&
4331 freq_included(channels, wpa_s->best_5_freq)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004332 params->freq = wpa_s->best_5_freq;
4333 wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
4334 "channel %d MHz", params->freq);
Dmitry Shmidt44c95782013-05-17 09:51:35 -07004335 } else if ((pref_freq = p2p_get_pref_freq(wpa_s->global->p2p,
4336 channels))) {
4337 params->freq = pref_freq;
4338 wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz from preferred "
4339 "channels", params->freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004340 } else {
Dmitry Shmidt04949592012-07-19 12:16:46 -07004341 int chan;
4342 for (chan = 0; chan < 11; chan++) {
4343 params->freq = 2412 + chan * 5;
4344 if (!wpas_p2p_disallowed_freq(wpa_s->global,
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004345 params->freq) &&
4346 freq_included(channels, params->freq))
Dmitry Shmidt04949592012-07-19 12:16:46 -07004347 break;
4348 }
4349 if (chan == 11) {
4350 wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel "
4351 "allowed");
4352 return -1;
4353 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004354 wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
4355 "known)", params->freq);
4356 }
4357
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07004358 freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
4359 if (!freqs)
4360 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004361
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07004362 res = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
4363 wpa_s->num_multichan_concurrent);
4364 if (res < 0) {
4365 os_free(freqs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004366 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004367 }
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07004368 num = res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004369
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07004370 if (!freq) {
4371 for (i = 0; i < num; i++) {
4372 if (freq_included(channels, freqs[i])) {
4373 wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
4374 freqs[i]);
4375 params->freq = freqs[i];
4376 break;
4377 }
4378 }
4379
4380 if (i == num) {
4381 if (num == wpa_s->num_multichan_concurrent) {
4382 wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
4383 os_free(freqs);
4384 return -1;
4385 } else {
4386 wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
4387 }
4388 }
4389 } else {
4390 for (i = 0; i < num; i++) {
4391 if (freqs[i] == freq)
4392 break;
4393 }
4394
4395 if (i == num) {
4396 if (num == wpa_s->num_multichan_concurrent) {
4397 wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
4398 os_free(freqs);
4399 return -1;
4400 } else {
4401 wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
4402 }
4403 }
4404 }
4405 os_free(freqs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004406 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004407}
4408
4409
4410static struct wpa_supplicant *
4411wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
4412 int go)
4413{
4414 struct wpa_supplicant *group_wpa_s;
4415
Dmitry Shmidtaa532512012-09-24 10:35:31 -07004416 if (!wpas_p2p_create_iface(wpa_s)) {
4417 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
4418 "operations");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004419 return wpa_s;
Dmitry Shmidtaa532512012-09-24 10:35:31 -07004420 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004421
4422 if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
Dmitry Shmidtaa532512012-09-24 10:35:31 -07004423 WPA_IF_P2P_CLIENT) < 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07004424 wpa_msg_global(wpa_s, MSG_ERROR,
4425 "P2P: Failed to add group interface");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004426 return NULL;
Dmitry Shmidtaa532512012-09-24 10:35:31 -07004427 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004428 group_wpa_s = wpas_p2p_init_group_interface(wpa_s, go);
4429 if (group_wpa_s == NULL) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07004430 wpa_msg_global(wpa_s, MSG_ERROR,
4431 "P2P: Failed to initialize group interface");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004432 wpas_p2p_remove_pending_group_interface(wpa_s);
4433 return NULL;
4434 }
4435
Dmitry Shmidtaa532512012-09-24 10:35:31 -07004436 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
4437 group_wpa_s->ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004438 return group_wpa_s;
4439}
4440
4441
4442/**
4443 * wpas_p2p_group_add - Add a new P2P group with local end as Group Owner
4444 * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
4445 * @persistent_group: Whether to create a persistent group
4446 * @freq: Frequency for the group or 0 to indicate no hardcoding
4447 * Returns: 0 on success, -1 on failure
4448 *
4449 * This function creates a new P2P group with the local end as the Group Owner,
4450 * i.e., without using Group Owner Negotiation.
4451 */
4452int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004453 int freq, int ht40)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004454{
4455 struct p2p_go_neg_results params;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004456
4457 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
4458 return -1;
4459
Dmitry Shmidtdca39792011-09-06 11:17:33 -07004460 /* Make sure we are not running find during connection establishment */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004461 wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004462 wpas_p2p_stop_find_oper(wpa_s);
Dmitry Shmidtdca39792011-09-06 11:17:33 -07004463
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004464 freq = wpas_p2p_select_go_freq(wpa_s, freq);
4465 if (freq < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004466 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004467
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004468 if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, NULL))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004469 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004470 if (params.freq &&
4471 !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
4472 wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
4473 "(%u MHz) is not supported for P2P uses",
4474 params.freq);
4475 return -1;
4476 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004477 p2p_go_params(wpa_s->global->p2p, &params);
4478 params.persistent_group = persistent_group;
4479
4480 wpa_s = wpas_p2p_get_group_iface(wpa_s, 0, 1);
4481 if (wpa_s == NULL)
4482 return -1;
4483 wpas_start_wps_go(wpa_s, &params, 0);
4484
4485 return 0;
4486}
4487
4488
4489static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
4490 struct wpa_ssid *params, int addr_allocated)
4491{
4492 struct wpa_ssid *ssid;
4493
4494 wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 0);
4495 if (wpa_s == NULL)
4496 return -1;
4497
4498 wpa_supplicant_ap_deinit(wpa_s);
4499
4500 ssid = wpa_config_add_network(wpa_s->conf);
4501 if (ssid == NULL)
4502 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004503 wpa_config_set_network_defaults(ssid);
4504 ssid->temporary = 1;
4505 ssid->proto = WPA_PROTO_RSN;
4506 ssid->pairwise_cipher = WPA_CIPHER_CCMP;
4507 ssid->group_cipher = WPA_CIPHER_CCMP;
4508 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
4509 ssid->ssid = os_malloc(params->ssid_len);
4510 if (ssid->ssid == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004511 wpa_config_remove_network(wpa_s->conf, ssid->id);
4512 return -1;
4513 }
4514 os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
4515 ssid->ssid_len = params->ssid_len;
4516 ssid->p2p_group = 1;
4517 ssid->export_keys = 1;
4518 if (params->psk_set) {
4519 os_memcpy(ssid->psk, params->psk, 32);
4520 ssid->psk_set = 1;
4521 }
4522 if (params->passphrase)
4523 ssid->passphrase = os_strdup(params->passphrase);
4524
4525 wpa_supplicant_select_network(wpa_s, ssid);
4526
4527 wpa_s->show_group_started = 1;
4528
4529 return 0;
4530}
4531
4532
4533int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
4534 struct wpa_ssid *ssid, int addr_allocated,
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004535 int freq, int ht40,
4536 const struct p2p_channels *channels)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004537{
4538 struct p2p_go_neg_results params;
4539 int go = 0;
4540
4541 if (ssid->disabled != 2 || ssid->ssid == NULL)
4542 return -1;
4543
4544 if (wpas_get_p2p_group(wpa_s, ssid->ssid, ssid->ssid_len, &go) &&
4545 go == (ssid->mode == WPAS_MODE_P2P_GO)) {
4546 wpa_printf(MSG_DEBUG, "P2P: Requested persistent group is "
4547 "already running");
4548 return 0;
4549 }
4550
4551 /* Make sure we are not running find during connection establishment */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004552 wpas_p2p_stop_find_oper(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004553
Dmitry Shmidt04949592012-07-19 12:16:46 -07004554 wpa_s->p2p_fallback_to_go_neg = 0;
4555
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004556 if (ssid->mode == WPAS_MODE_INFRA)
4557 return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
4558
4559 if (ssid->mode != WPAS_MODE_P2P_GO)
4560 return -1;
4561
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004562 freq = wpas_p2p_select_go_freq(wpa_s, freq);
4563 if (freq < 0)
4564 return -1;
4565
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004566 if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, channels))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004567 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004568
4569 params.role_go = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004570 params.psk_set = ssid->psk_set;
4571 if (params.psk_set)
4572 os_memcpy(params.psk, ssid->psk, sizeof(params.psk));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004573 if (ssid->passphrase) {
4574 if (os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
4575 wpa_printf(MSG_ERROR, "P2P: Invalid passphrase in "
4576 "persistent group");
4577 return -1;
4578 }
4579 os_strlcpy(params.passphrase, ssid->passphrase,
4580 sizeof(params.passphrase));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004581 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004582 os_memcpy(params.ssid, ssid->ssid, ssid->ssid_len);
4583 params.ssid_len = ssid->ssid_len;
4584 params.persistent_group = 1;
4585
4586 wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 1);
4587 if (wpa_s == NULL)
4588 return -1;
4589
4590 wpas_start_wps_go(wpa_s, &params, 0);
4591
4592 return 0;
4593}
4594
4595
4596static void wpas_p2p_ie_update(void *ctx, struct wpabuf *beacon_ies,
4597 struct wpabuf *proberesp_ies)
4598{
4599 struct wpa_supplicant *wpa_s = ctx;
4600 if (wpa_s->ap_iface) {
4601 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004602 if (!(hapd->conf->p2p & P2P_GROUP_OWNER)) {
4603 wpabuf_free(beacon_ies);
4604 wpabuf_free(proberesp_ies);
4605 return;
4606 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004607 if (beacon_ies) {
4608 wpabuf_free(hapd->p2p_beacon_ie);
4609 hapd->p2p_beacon_ie = beacon_ies;
4610 }
4611 wpabuf_free(hapd->p2p_probe_resp_ie);
4612 hapd->p2p_probe_resp_ie = proberesp_ies;
4613 } else {
4614 wpabuf_free(beacon_ies);
4615 wpabuf_free(proberesp_ies);
4616 }
4617 wpa_supplicant_ap_update_beacon(wpa_s);
4618}
4619
4620
4621static void wpas_p2p_idle_update(void *ctx, int idle)
4622{
4623 struct wpa_supplicant *wpa_s = ctx;
4624 if (!wpa_s->ap_iface)
4625 return;
4626 wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not ");
Dmitry Shmidt04949592012-07-19 12:16:46 -07004627 if (idle)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004628 wpas_p2p_set_group_idle_timeout(wpa_s);
4629 else
4630 eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
4631}
4632
4633
4634struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
Dmitry Shmidt04949592012-07-19 12:16:46 -07004635 struct wpa_ssid *ssid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004636{
4637 struct p2p_group *group;
4638 struct p2p_group_config *cfg;
4639
4640 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
4641 return NULL;
4642 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
4643 return NULL;
4644
4645 cfg = os_zalloc(sizeof(*cfg));
4646 if (cfg == NULL)
4647 return NULL;
4648
Dmitry Shmidt04949592012-07-19 12:16:46 -07004649 if (ssid->p2p_persistent_group && wpa_s->conf->persistent_reconnect)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004650 cfg->persistent_group = 2;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004651 else if (ssid->p2p_persistent_group)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004652 cfg->persistent_group = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004653 os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN);
4654 if (wpa_s->max_stations &&
4655 wpa_s->max_stations < wpa_s->conf->max_num_sta)
4656 cfg->max_clients = wpa_s->max_stations;
4657 else
4658 cfg->max_clients = wpa_s->conf->max_num_sta;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004659 os_memcpy(cfg->ssid, ssid->ssid, ssid->ssid_len);
4660 cfg->ssid_len = ssid->ssid_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004661 cfg->cb_ctx = wpa_s;
4662 cfg->ie_update = wpas_p2p_ie_update;
4663 cfg->idle_update = wpas_p2p_idle_update;
4664
4665 group = p2p_group_init(wpa_s->global->p2p, cfg);
4666 if (group == NULL)
4667 os_free(cfg);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004668 if (ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004669 p2p_group_notif_formation_done(group);
4670 wpa_s->p2p_group = group;
4671 return group;
4672}
4673
4674
4675void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
4676 int registrar)
4677{
Dmitry Shmidt04949592012-07-19 12:16:46 -07004678 struct wpa_ssid *ssid = wpa_s->current_ssid;
4679
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004680 if (!wpa_s->p2p_in_provisioning) {
4681 wpa_printf(MSG_DEBUG, "P2P: Ignore WPS success event - P2P "
4682 "provisioning not in progress");
4683 return;
4684 }
4685
Dmitry Shmidt04949592012-07-19 12:16:46 -07004686 if (ssid && ssid->mode == WPAS_MODE_INFRA) {
4687 u8 go_dev_addr[ETH_ALEN];
4688 os_memcpy(go_dev_addr, wpa_s->bssid, ETH_ALEN);
4689 wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid,
4690 ssid->ssid_len);
4691 /* Clear any stored provisioning info */
4692 p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr);
4693 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004694
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004695 eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
4696 NULL);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004697 if (ssid && ssid->mode == WPAS_MODE_INFRA) {
4698 /*
4699 * Use a separate timeout for initial data connection to
4700 * complete to allow the group to be removed automatically if
4701 * something goes wrong in this step before the P2P group idle
4702 * timeout mechanism is taken into use.
4703 */
4704 eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
4705 wpas_p2p_group_formation_timeout,
4706 wpa_s->parent, NULL);
4707 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004708 if (wpa_s->global->p2p)
4709 p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
4710 else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
4711 wpa_drv_wps_success_cb(wpa_s, peer_addr);
4712 wpas_group_formation_completed(wpa_s, 1);
4713}
4714
4715
Jouni Malinen75ecf522011-06-27 15:19:46 -07004716void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
4717 struct wps_event_fail *fail)
4718{
4719 if (!wpa_s->p2p_in_provisioning) {
4720 wpa_printf(MSG_DEBUG, "P2P: Ignore WPS fail event - P2P "
4721 "provisioning not in progress");
4722 return;
4723 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004724
4725 if (wpa_s->go_params) {
4726 p2p_clear_provisioning_info(
4727 wpa_s->global->p2p,
Dmitry Shmidt04949592012-07-19 12:16:46 -07004728 wpa_s->go_params->peer_device_addr);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004729 }
4730
Jouni Malinen75ecf522011-06-27 15:19:46 -07004731 wpas_notify_p2p_wps_failed(wpa_s, fail);
4732}
4733
4734
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004735int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
Dmitry Shmidt04949592012-07-19 12:16:46 -07004736 const char *config_method,
4737 enum wpas_p2p_prov_disc_use use)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004738{
4739 u16 config_methods;
4740
Dmitry Shmidt04949592012-07-19 12:16:46 -07004741 wpa_s->p2p_fallback_to_go_neg = 0;
4742 wpa_s->pending_pd_use = NORMAL_PD;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004743 if (os_strncmp(config_method, "display", 7) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004744 config_methods = WPS_CONFIG_DISPLAY;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004745 else if (os_strncmp(config_method, "keypad", 6) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004746 config_methods = WPS_CONFIG_KEYPAD;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004747 else if (os_strncmp(config_method, "pbc", 3) == 0 ||
4748 os_strncmp(config_method, "pushbutton", 10) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004749 config_methods = WPS_CONFIG_PUSHBUTTON;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004750 else {
4751 wpa_printf(MSG_DEBUG, "P2P: Unknown config method");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004752 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004753 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004754
Dmitry Shmidt04949592012-07-19 12:16:46 -07004755 if (use == WPAS_P2P_PD_AUTO) {
4756 os_memcpy(wpa_s->pending_join_dev_addr, peer_addr, ETH_ALEN);
4757 wpa_s->pending_pd_config_methods = config_methods;
4758 wpa_s->p2p_auto_pd = 1;
4759 wpa_s->p2p_auto_join = 0;
4760 wpa_s->pending_pd_before_join = 0;
4761 wpa_s->auto_pd_scan_retry = 0;
4762 wpas_p2p_stop_find(wpa_s);
4763 wpa_s->p2p_join_scan_count = 0;
4764 os_get_time(&wpa_s->p2p_auto_started);
4765 wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld",
4766 wpa_s->p2p_auto_started.sec,
4767 wpa_s->p2p_auto_started.usec);
4768 wpas_p2p_join_scan(wpa_s, NULL);
4769 return 0;
4770 }
4771
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004772 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
4773 return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
Dmitry Shmidt04949592012-07-19 12:16:46 -07004774 config_methods,
4775 use == WPAS_P2P_PD_FOR_JOIN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004776 }
4777
4778 if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
4779 return -1;
4780
4781 return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
Dmitry Shmidt04949592012-07-19 12:16:46 -07004782 config_methods, use == WPAS_P2P_PD_FOR_JOIN,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004783 0, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004784}
4785
4786
4787int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
4788 char *end)
4789{
4790 return p2p_scan_result_text(ies, ies_len, buf, end);
4791}
4792
4793
4794static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
4795{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004796 if (!offchannel_pending_action_tx(wpa_s))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004797 return;
4798
4799 wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
4800 "operation request");
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004801 offchannel_clear_pending_action_tx(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004802}
4803
4804
4805int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
4806 enum p2p_discovery_type type,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004807 unsigned int num_req_dev_types, const u8 *req_dev_types,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004808 const u8 *dev_id, unsigned int search_delay)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004809{
4810 wpas_p2p_clear_pending_action_tx(wpa_s);
4811 wpa_s->p2p_long_listen = 0;
4812
4813 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
4814 return wpa_drv_p2p_find(wpa_s, timeout, type);
4815
Dmitry Shmidt04949592012-07-19 12:16:46 -07004816 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
4817 wpa_s->p2p_in_provisioning)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004818 return -1;
4819
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004820 wpa_supplicant_cancel_sched_scan(wpa_s);
4821
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004822 return p2p_find(wpa_s->global->p2p, timeout, type,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004823 num_req_dev_types, req_dev_types, dev_id,
4824 search_delay);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004825}
4826
4827
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004828static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004829{
4830 wpas_p2p_clear_pending_action_tx(wpa_s);
4831 wpa_s->p2p_long_listen = 0;
4832 eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
4833 eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
Jouni Malinendc7b7132012-09-14 12:53:47 -07004834 wpa_s->global->p2p_cb_on_scan_complete = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004835
4836 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
4837 wpa_drv_p2p_stop_find(wpa_s);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004838 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004839 }
4840
4841 if (wpa_s->global->p2p)
4842 p2p_stop_find(wpa_s->global->p2p);
4843
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004844 return 0;
4845}
4846
4847
4848void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
4849{
4850 if (wpas_p2p_stop_find_oper(wpa_s) > 0)
4851 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004852 wpas_p2p_remove_pending_group_interface(wpa_s);
4853}
4854
4855
4856static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx)
4857{
4858 struct wpa_supplicant *wpa_s = eloop_ctx;
4859 wpa_s->p2p_long_listen = 0;
4860}
4861
4862
4863int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
4864{
4865 int res;
4866
4867 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
4868 return -1;
4869
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004870 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004871 wpas_p2p_clear_pending_action_tx(wpa_s);
4872
4873 if (timeout == 0) {
4874 /*
4875 * This is a request for unlimited Listen state. However, at
4876 * least for now, this is mapped to a Listen state for one
4877 * hour.
4878 */
4879 timeout = 3600;
4880 }
4881 eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
4882 wpa_s->p2p_long_listen = 0;
4883
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004884 /*
4885 * Stop previous find/listen operation to avoid trying to request a new
4886 * remain-on-channel operation while the driver is still running the
4887 * previous one.
4888 */
4889 if (wpa_s->global->p2p)
4890 p2p_stop_find(wpa_s->global->p2p);
4891
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004892 res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
4893 if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
4894 wpa_s->p2p_long_listen = timeout * 1000;
4895 eloop_register_timeout(timeout, 0,
4896 wpas_p2p_long_listen_timeout,
4897 wpa_s, NULL);
4898 }
4899
4900 return res;
4901}
4902
4903
4904int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
4905 u8 *buf, size_t len, int p2p_group)
4906{
4907 struct wpabuf *p2p_ie;
4908 int ret;
4909
4910 if (wpa_s->global->p2p_disabled)
4911 return -1;
4912 if (wpa_s->global->p2p == NULL)
4913 return -1;
4914 if (bss == NULL)
4915 return -1;
4916
4917 p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
4918 ret = p2p_assoc_req_ie(wpa_s->global->p2p, bss->bssid, buf, len,
4919 p2p_group, p2p_ie);
4920 wpabuf_free(p2p_ie);
4921
4922 return ret;
4923}
4924
4925
4926int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004927 const u8 *dst, const u8 *bssid,
Dmitry Shmidt04949592012-07-19 12:16:46 -07004928 const u8 *ie, size_t ie_len, int ssi_signal)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004929{
4930 if (wpa_s->global->p2p_disabled)
4931 return 0;
4932 if (wpa_s->global->p2p == NULL)
4933 return 0;
4934
Dmitry Shmidt04949592012-07-19 12:16:46 -07004935 switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
4936 ie, ie_len)) {
4937 case P2P_PREQ_NOT_P2P:
4938 wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
4939 ssi_signal);
4940 /* fall through */
4941 case P2P_PREQ_MALFORMED:
4942 case P2P_PREQ_NOT_LISTEN:
4943 case P2P_PREQ_NOT_PROCESSED:
4944 default: /* make gcc happy */
4945 return 0;
4946 case P2P_PREQ_PROCESSED:
4947 return 1;
4948 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004949}
4950
4951
4952void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
4953 const u8 *sa, const u8 *bssid,
4954 u8 category, const u8 *data, size_t len, int freq)
4955{
4956 if (wpa_s->global->p2p_disabled)
4957 return;
4958 if (wpa_s->global->p2p == NULL)
4959 return;
4960
4961 p2p_rx_action(wpa_s->global->p2p, da, sa, bssid, category, data, len,
4962 freq);
4963}
4964
4965
4966void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies)
4967{
4968 if (wpa_s->global->p2p_disabled)
4969 return;
4970 if (wpa_s->global->p2p == NULL)
4971 return;
4972
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004973 p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004974}
4975
4976
4977void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
4978{
4979 p2p_group_deinit(wpa_s->p2p_group);
4980 wpa_s->p2p_group = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004981
4982 wpa_s->ap_configured_cb = NULL;
4983 wpa_s->ap_configured_cb_ctx = NULL;
4984 wpa_s->ap_configured_cb_data = NULL;
4985 wpa_s->connect_without_scan = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004986}
4987
4988
4989int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
4990{
4991 wpa_s->p2p_long_listen = 0;
4992
4993 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
4994 return wpa_drv_p2p_reject(wpa_s, addr);
4995
4996 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
4997 return -1;
4998
4999 return p2p_reject(wpa_s->global->p2p, addr);
5000}
5001
5002
5003/* Invite to reinvoke a persistent group */
5004int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
Jouni Malinen31be0a42012-08-31 21:20:51 +03005005 struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005006 int ht40, int pref_freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005007{
5008 enum p2p_invite_role role;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005009 u8 *bssid = NULL;
5010 int force_freq = 0;
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005011 int res;
5012
Dmitry Shmidt700a1372013-03-15 14:14:44 -07005013 wpa_s->global->p2p_invite_group = NULL;
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005014 if (peer_addr)
5015 os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
5016 else
5017 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005018
Jouni Malinen31be0a42012-08-31 21:20:51 +03005019 wpa_s->p2p_persistent_go_freq = freq;
5020 wpa_s->p2p_go_ht40 = !!ht40;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005021 if (ssid->mode == WPAS_MODE_P2P_GO) {
5022 role = P2P_INVITE_ROLE_GO;
5023 if (peer_addr == NULL) {
5024 wpa_printf(MSG_DEBUG, "P2P: Missing peer "
5025 "address in invitation command");
5026 return -1;
5027 }
5028 if (wpas_p2p_create_iface(wpa_s)) {
5029 if (wpas_p2p_add_group_interface(wpa_s,
5030 WPA_IF_P2P_GO) < 0) {
5031 wpa_printf(MSG_ERROR, "P2P: Failed to "
5032 "allocate a new interface for the "
5033 "group");
5034 return -1;
5035 }
5036 bssid = wpa_s->pending_interface_addr;
5037 } else
5038 bssid = wpa_s->own_addr;
5039 } else {
5040 role = P2P_INVITE_ROLE_CLIENT;
5041 peer_addr = ssid->bssid;
5042 }
5043 wpa_s->pending_invite_ssid_id = ssid->id;
5044
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005045 res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005046 if (res)
5047 return res;
Irfan Sheriffaf84a572012-09-22 16:59:30 -07005048
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005049 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
5050 return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
5051 ssid->ssid, ssid->ssid_len,
5052 go_dev_addr, 1);
5053
5054 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
5055 return -1;
5056
5057 return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005058 ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
5059 1, pref_freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005060}
5061
5062
5063/* Invite to join an active group */
5064int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
5065 const u8 *peer_addr, const u8 *go_dev_addr)
5066{
5067 struct wpa_global *global = wpa_s->global;
5068 enum p2p_invite_role role;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005069 u8 *bssid = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005070 struct wpa_ssid *ssid;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005071 int persistent;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005072 int force_freq = 0, pref_freq = 0;
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005073 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005074
Jouni Malinen31be0a42012-08-31 21:20:51 +03005075 wpa_s->p2p_persistent_go_freq = 0;
5076 wpa_s->p2p_go_ht40 = 0;
5077
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005078 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
5079 if (os_strcmp(wpa_s->ifname, ifname) == 0)
5080 break;
5081 }
5082 if (wpa_s == NULL) {
5083 wpa_printf(MSG_DEBUG, "P2P: Interface '%s' not found", ifname);
5084 return -1;
5085 }
5086
5087 ssid = wpa_s->current_ssid;
5088 if (ssid == NULL) {
5089 wpa_printf(MSG_DEBUG, "P2P: No current SSID to use for "
5090 "invitation");
5091 return -1;
5092 }
5093
Dmitry Shmidt700a1372013-03-15 14:14:44 -07005094 wpa_s->global->p2p_invite_group = wpa_s;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005095 persistent = ssid->p2p_persistent_group &&
5096 wpas_p2p_get_persistent(wpa_s->parent, peer_addr,
5097 ssid->ssid, ssid->ssid_len);
5098
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005099 if (ssid->mode == WPAS_MODE_P2P_GO) {
5100 role = P2P_INVITE_ROLE_ACTIVE_GO;
5101 bssid = wpa_s->own_addr;
5102 if (go_dev_addr == NULL)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005103 go_dev_addr = wpa_s->global->p2p_dev_addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005104 } else {
5105 role = P2P_INVITE_ROLE_CLIENT;
5106 if (wpa_s->wpa_state < WPA_ASSOCIATED) {
5107 wpa_printf(MSG_DEBUG, "P2P: Not associated - cannot "
5108 "invite to current group");
5109 return -1;
5110 }
5111 bssid = wpa_s->bssid;
5112 if (go_dev_addr == NULL &&
5113 !is_zero_ether_addr(wpa_s->go_dev_addr))
5114 go_dev_addr = wpa_s->go_dev_addr;
5115 }
5116 wpa_s->parent->pending_invite_ssid_id = -1;
5117
5118 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
5119 return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
5120 ssid->ssid, ssid->ssid_len,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005121 go_dev_addr, persistent);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005122
5123 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
5124 return -1;
5125
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005126 res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq);
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005127 if (res)
5128 return res;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005129 wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005130
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005131 return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005132 ssid->ssid, ssid->ssid_len, force_freq,
5133 go_dev_addr, persistent, pref_freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005134}
5135
5136
5137void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
5138{
5139 struct wpa_ssid *ssid = wpa_s->current_ssid;
5140 const char *ssid_txt;
5141 u8 go_dev_addr[ETH_ALEN];
Jouni Malinen75ecf522011-06-27 15:19:46 -07005142 int network_id = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005143 int persistent;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005144 int freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005145
Dmitry Shmidt04949592012-07-19 12:16:46 -07005146 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
5147 eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
5148 wpa_s->parent, NULL);
5149 }
5150
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005151 if (!wpa_s->show_group_started || !ssid)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005152 goto done;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005153
5154 wpa_s->show_group_started = 0;
5155
5156 ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
5157 os_memset(go_dev_addr, 0, ETH_ALEN);
5158 if (ssid->bssid_set)
5159 os_memcpy(go_dev_addr, ssid->bssid, ETH_ALEN);
5160 persistent = wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid,
5161 ssid->ssid_len);
5162 os_memcpy(wpa_s->go_dev_addr, go_dev_addr, ETH_ALEN);
5163
5164 if (wpa_s->global->p2p_group_formation == wpa_s)
5165 wpa_s->global->p2p_group_formation = NULL;
5166
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005167 freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
5168 (int) wpa_s->assoc_freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005169 if (ssid->passphrase == NULL && ssid->psk_set) {
5170 char psk[65];
5171 wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07005172 wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
5173 "%s client ssid=\"%s\" freq=%d psk=%s "
5174 "go_dev_addr=" MACSTR "%s",
5175 wpa_s->ifname, ssid_txt, freq, psk,
5176 MAC2STR(go_dev_addr),
5177 persistent ? " [PERSISTENT]" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005178 } else {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07005179 wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
5180 "%s client ssid=\"%s\" freq=%d "
5181 "passphrase=\"%s\" go_dev_addr=" MACSTR "%s",
5182 wpa_s->ifname, ssid_txt, freq,
5183 ssid->passphrase ? ssid->passphrase : "",
5184 MAC2STR(go_dev_addr),
5185 persistent ? " [PERSISTENT]" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005186 }
5187
5188 if (persistent)
Jouni Malinen75ecf522011-06-27 15:19:46 -07005189 network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
5190 ssid, go_dev_addr);
5191 if (network_id < 0)
5192 network_id = ssid->id;
5193 wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005194
5195done:
Dmitry Shmidt37d4d6a2013-03-18 13:09:42 -07005196 wpas_p2p_continue_after_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005197}
5198
5199
5200int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
5201 u32 interval1, u32 duration2, u32 interval2)
5202{
5203 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
5204 return -1;
5205 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
5206 return -1;
5207
5208 if (wpa_s->wpa_state < WPA_ASSOCIATED ||
5209 wpa_s->current_ssid == NULL ||
5210 wpa_s->current_ssid->mode != WPAS_MODE_INFRA)
5211 return -1;
5212
5213 return p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
5214 wpa_s->own_addr, wpa_s->assoc_freq,
5215 duration1, interval1, duration2, interval2);
5216}
5217
5218
5219int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
5220 unsigned int interval)
5221{
5222 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
5223 return -1;
5224
5225 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
5226 return -1;
5227
5228 return p2p_ext_listen(wpa_s->global->p2p, period, interval);
5229}
5230
5231
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005232static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
5233{
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005234 if (wpa_s->current_ssid == NULL) {
5235 /*
5236 * current_ssid can be cleared when P2P client interface gets
5237 * disconnected, so assume this interface was used as P2P
5238 * client.
5239 */
5240 return 1;
5241 }
5242 return wpa_s->current_ssid->p2p_group &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005243 wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
5244}
5245
5246
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005247static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
5248{
5249 struct wpa_supplicant *wpa_s = eloop_ctx;
5250
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005251 if (wpa_s->conf->p2p_group_idle == 0 && !wpas_p2p_is_client(wpa_s)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005252 wpa_printf(MSG_DEBUG, "P2P: Ignore group idle timeout - "
5253 "disabled");
5254 return;
5255 }
5256
Dmitry Shmidt04949592012-07-19 12:16:46 -07005257 wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
5258 "group");
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005259 wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_IDLE_TIMEOUT);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005260}
5261
5262
5263static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
5264{
Dmitry Shmidt04949592012-07-19 12:16:46 -07005265 int timeout;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005266
Dmitry Shmidt04949592012-07-19 12:16:46 -07005267 if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
5268 wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
5269
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005270 if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
5271 return;
5272
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005273 timeout = wpa_s->conf->p2p_group_idle;
5274 if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
5275 (timeout == 0 || timeout > P2P_MAX_CLIENT_IDLE))
5276 timeout = P2P_MAX_CLIENT_IDLE;
5277
5278 if (timeout == 0)
5279 return;
5280
Dmitry Shmidt04949592012-07-19 12:16:46 -07005281 if (timeout < 0) {
5282 if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA)
5283 timeout = 0; /* special client mode no-timeout */
5284 else
5285 return;
5286 }
5287
5288 if (wpa_s->p2p_in_provisioning) {
5289 /*
5290 * Use the normal group formation timeout during the
5291 * provisioning phase to avoid terminating this process too
5292 * early due to group idle timeout.
5293 */
5294 wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
5295 "during provisioning");
5296 return;
5297 }
Deepthi Gowri9e4e8ac2013-04-16 11:57:05 +05305298
Dmitry Shmidt04949592012-07-19 12:16:46 -07005299 if (wpa_s->show_group_started) {
5300 /*
5301 * Use the normal group formation timeout between the end of
5302 * the provisioning phase and completion of 4-way handshake to
5303 * avoid terminating this process too early due to group idle
5304 * timeout.
5305 */
5306 wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
5307 "while waiting for initial 4-way handshake to "
5308 "complete");
5309 return;
5310 }
5311
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005312 wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005313 timeout);
5314 eloop_register_timeout(timeout, 0, wpas_p2p_group_idle_timeout,
5315 wpa_s, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005316}
5317
5318
Jouni Malinen2b89da82012-08-31 22:04:41 +03005319/* Returns 1 if the interface was removed */
5320int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
5321 u16 reason_code, const u8 *ie, size_t ie_len,
5322 int locally_generated)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005323{
5324 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
Jouni Malinen2b89da82012-08-31 22:04:41 +03005325 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005326 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
Jouni Malinen2b89da82012-08-31 22:04:41 +03005327 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005328
Dmitry Shmidt04949592012-07-19 12:16:46 -07005329 if (!locally_generated)
5330 p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie,
5331 ie_len);
5332
5333 if (reason_code == WLAN_REASON_DEAUTH_LEAVING && !locally_generated &&
5334 wpa_s->current_ssid &&
5335 wpa_s->current_ssid->p2p_group &&
5336 wpa_s->current_ssid->mode == WPAS_MODE_INFRA) {
5337 wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group "
5338 "session is ending");
Jouni Malinen2b89da82012-08-31 22:04:41 +03005339 if (wpas_p2p_group_delete(wpa_s,
5340 P2P_GROUP_REMOVAL_GO_ENDING_SESSION)
5341 > 0)
5342 return 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005343 }
Jouni Malinen2b89da82012-08-31 22:04:41 +03005344
5345 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005346}
5347
5348
5349void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
Dmitry Shmidt04949592012-07-19 12:16:46 -07005350 u16 reason_code, const u8 *ie, size_t ie_len,
5351 int locally_generated)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005352{
5353 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
5354 return;
5355 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
5356 return;
5357
Dmitry Shmidt04949592012-07-19 12:16:46 -07005358 if (!locally_generated)
5359 p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie,
5360 ie_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005361}
5362
5363
5364void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
5365{
5366 struct p2p_data *p2p = wpa_s->global->p2p;
5367
5368 if (p2p == NULL)
5369 return;
5370
5371 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
5372 return;
5373
5374 if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_NAME)
5375 p2p_set_dev_name(p2p, wpa_s->conf->device_name);
5376
5377 if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
5378 p2p_set_pri_dev_type(p2p, wpa_s->conf->device_type);
5379
5380 if (wpa_s->wps &&
5381 (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS))
5382 p2p_set_config_methods(p2p, wpa_s->wps->config_methods);
5383
5384 if (wpa_s->wps && (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID))
5385 p2p_set_uuid(p2p, wpa_s->wps->uuid);
5386
5387 if (wpa_s->conf->changed_parameters & CFG_CHANGED_WPS_STRING) {
5388 p2p_set_manufacturer(p2p, wpa_s->conf->manufacturer);
5389 p2p_set_model_name(p2p, wpa_s->conf->model_name);
5390 p2p_set_model_number(p2p, wpa_s->conf->model_number);
5391 p2p_set_serial_number(p2p, wpa_s->conf->serial_number);
5392 }
5393
5394 if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE)
5395 p2p_set_sec_dev_types(p2p,
5396 (void *) wpa_s->conf->sec_device_type,
5397 wpa_s->conf->num_sec_device_types);
5398
5399 if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION) {
5400 int i;
5401 p2p_remove_wps_vendor_extensions(p2p);
5402 for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
5403 if (wpa_s->conf->wps_vendor_ext[i] == NULL)
5404 continue;
5405 p2p_add_wps_vendor_extension(
5406 p2p, wpa_s->conf->wps_vendor_ext[i]);
5407 }
5408 }
5409
5410 if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
5411 wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
5412 char country[3];
5413 country[0] = wpa_s->conf->country[0];
5414 country[1] = wpa_s->conf->country[1];
5415 country[2] = 0x04;
5416 p2p_set_country(p2p, country);
5417 }
5418
5419 if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_SSID_POSTFIX) {
5420 p2p_set_ssid_postfix(p2p, (u8 *) wpa_s->conf->p2p_ssid_postfix,
5421 wpa_s->conf->p2p_ssid_postfix ?
5422 os_strlen(wpa_s->conf->p2p_ssid_postfix) :
5423 0);
5424 }
5425
5426 if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_INTRA_BSS)
5427 p2p_set_intra_bss_dist(p2p, wpa_s->conf->p2p_intra_bss);
Jouni Malinen75ecf522011-06-27 15:19:46 -07005428
5429 if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_LISTEN_CHANNEL) {
5430 u8 reg_class, channel;
5431 int ret;
5432 unsigned int r;
5433 if (wpa_s->conf->p2p_listen_reg_class &&
5434 wpa_s->conf->p2p_listen_channel) {
5435 reg_class = wpa_s->conf->p2p_listen_reg_class;
5436 channel = wpa_s->conf->p2p_listen_channel;
5437 } else {
5438 reg_class = 81;
5439 /*
5440 * Pick one of the social channels randomly as the
5441 * listen channel.
5442 */
5443 os_get_random((u8 *) &r, sizeof(r));
5444 channel = 1 + (r % 3) * 5;
5445 }
5446 ret = p2p_set_listen_channel(p2p, reg_class, channel);
5447 if (ret)
5448 wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
5449 "failed: %d", ret);
5450 }
5451 if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_OPER_CHANNEL) {
5452 u8 op_reg_class, op_channel, cfg_op_channel;
5453 int ret = 0;
5454 unsigned int r;
5455 if (wpa_s->conf->p2p_oper_reg_class &&
5456 wpa_s->conf->p2p_oper_channel) {
5457 op_reg_class = wpa_s->conf->p2p_oper_reg_class;
5458 op_channel = wpa_s->conf->p2p_oper_channel;
5459 cfg_op_channel = 1;
5460 } else {
5461 op_reg_class = 81;
5462 /*
5463 * Use random operation channel from (1, 6, 11)
5464 *if no other preference is indicated.
5465 */
5466 os_get_random((u8 *) &r, sizeof(r));
5467 op_channel = 1 + (r % 3) * 5;
5468 cfg_op_channel = 0;
5469 }
5470 ret = p2p_set_oper_channel(p2p, op_reg_class, op_channel,
5471 cfg_op_channel);
5472 if (ret)
5473 wpa_printf(MSG_ERROR, "P2P: Own oper channel update "
5474 "failed: %d", ret);
5475 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07005476
5477 if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_PREF_CHAN) {
5478 if (p2p_set_pref_chan(p2p, wpa_s->conf->num_p2p_pref_chan,
5479 wpa_s->conf->p2p_pref_chan) < 0) {
5480 wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
5481 "update failed");
5482 }
5483 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005484}
5485
5486
5487int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
5488 int duration)
5489{
5490 if (!wpa_s->ap_iface)
5491 return -1;
5492 return hostapd_p2p_set_noa(wpa_s->ap_iface->bss[0], count, start,
5493 duration);
5494}
5495
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005496
5497int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
5498{
5499 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
5500 return -1;
5501 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
5502 return -1;
5503
5504 wpa_s->global->cross_connection = enabled;
5505 p2p_set_cross_connect(wpa_s->global->p2p, enabled);
5506
5507 if (!enabled) {
5508 struct wpa_supplicant *iface;
5509
5510 for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
5511 {
5512 if (iface->cross_connect_enabled == 0)
5513 continue;
5514
5515 iface->cross_connect_enabled = 0;
5516 iface->cross_connect_in_use = 0;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07005517 wpa_msg_global(iface->parent, MSG_INFO,
5518 P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
5519 iface->ifname,
5520 iface->cross_connect_uplink);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005521 }
5522 }
5523
5524 return 0;
5525}
5526
5527
5528static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
5529{
5530 struct wpa_supplicant *iface;
5531
5532 if (!uplink->global->cross_connection)
5533 return;
5534
5535 for (iface = uplink->global->ifaces; iface; iface = iface->next) {
5536 if (!iface->cross_connect_enabled)
5537 continue;
5538 if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) !=
5539 0)
5540 continue;
5541 if (iface->ap_iface == NULL)
5542 continue;
5543 if (iface->cross_connect_in_use)
5544 continue;
5545
5546 iface->cross_connect_in_use = 1;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07005547 wpa_msg_global(iface->parent, MSG_INFO,
5548 P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
5549 iface->ifname, iface->cross_connect_uplink);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005550 }
5551}
5552
5553
5554static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
5555{
5556 struct wpa_supplicant *iface;
5557
5558 for (iface = uplink->global->ifaces; iface; iface = iface->next) {
5559 if (!iface->cross_connect_enabled)
5560 continue;
5561 if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) !=
5562 0)
5563 continue;
5564 if (!iface->cross_connect_in_use)
5565 continue;
5566
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07005567 wpa_msg_global(iface->parent, MSG_INFO,
5568 P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
5569 iface->ifname, iface->cross_connect_uplink);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005570 iface->cross_connect_in_use = 0;
5571 }
5572}
5573
5574
5575void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
5576{
5577 if (wpa_s->ap_iface || wpa_s->current_ssid == NULL ||
5578 wpa_s->current_ssid->mode != WPAS_MODE_INFRA ||
5579 wpa_s->cross_connect_disallowed)
5580 wpas_p2p_disable_cross_connect(wpa_s);
5581 else
5582 wpas_p2p_enable_cross_connect(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005583 if (!wpa_s->ap_iface &&
5584 eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
5585 wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005586}
5587
5588
5589void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
5590{
5591 wpas_p2p_disable_cross_connect(wpa_s);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005592 if (!wpa_s->ap_iface &&
5593 !eloop_is_timeout_registered(wpas_p2p_group_idle_timeout,
5594 wpa_s, NULL))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005595 wpas_p2p_set_group_idle_timeout(wpa_s);
5596}
5597
5598
5599static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
5600{
5601 struct wpa_supplicant *iface;
5602
5603 if (!wpa_s->global->cross_connection)
5604 return;
5605
5606 for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
5607 if (iface == wpa_s)
5608 continue;
5609 if (iface->drv_flags &
5610 WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)
5611 continue;
5612 if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)
5613 continue;
5614
5615 wpa_s->cross_connect_enabled = 1;
5616 os_strlcpy(wpa_s->cross_connect_uplink, iface->ifname,
5617 sizeof(wpa_s->cross_connect_uplink));
5618 wpa_printf(MSG_DEBUG, "P2P: Enable cross connection from "
5619 "%s to %s whenever uplink is available",
5620 wpa_s->ifname, wpa_s->cross_connect_uplink);
5621
5622 if (iface->ap_iface || iface->current_ssid == NULL ||
5623 iface->current_ssid->mode != WPAS_MODE_INFRA ||
5624 iface->cross_connect_disallowed ||
5625 iface->wpa_state != WPA_COMPLETED)
5626 break;
5627
5628 wpa_s->cross_connect_in_use = 1;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07005629 wpa_msg_global(wpa_s->parent, MSG_INFO,
5630 P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
5631 wpa_s->ifname, wpa_s->cross_connect_uplink);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005632 break;
5633 }
5634}
5635
5636
5637int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
5638{
5639 if (wpa_s->p2p_group_interface != P2P_GROUP_INTERFACE_CLIENT &&
5640 !wpa_s->p2p_in_provisioning)
5641 return 0; /* not P2P client operation */
5642
5643 wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC "
5644 "session overlap");
5645 if (wpa_s != wpa_s->parent)
5646 wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005647 wpas_p2p_group_formation_failed(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005648 return 1;
5649}
5650
5651
5652void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
5653{
5654 struct p2p_channels chan;
5655
5656 if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
5657 return;
5658
5659 os_memset(&chan, 0, sizeof(chan));
5660 if (wpas_p2p_setup_channels(wpa_s, &chan)) {
5661 wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
5662 "channel list");
5663 return;
5664 }
5665
5666 p2p_update_channel_list(wpa_s->global->p2p, &chan);
5667}
5668
5669
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005670static void wpas_p2p_scan_res_ignore(struct wpa_supplicant *wpa_s,
5671 struct wpa_scan_results *scan_res)
5672{
5673 wpa_printf(MSG_DEBUG, "P2P: Ignore scan results");
5674}
5675
5676
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005677int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
5678{
5679 struct wpa_global *global = wpa_s->global;
5680 int found = 0;
5681 const u8 *peer;
5682
5683 if (global->p2p == NULL)
5684 return -1;
5685
5686 wpa_printf(MSG_DEBUG, "P2P: Request to cancel group formation");
5687
5688 if (wpa_s->pending_interface_name[0] &&
5689 !is_zero_ether_addr(wpa_s->pending_interface_addr))
5690 found = 1;
5691
5692 peer = p2p_get_go_neg_peer(global->p2p);
5693 if (peer) {
5694 wpa_printf(MSG_DEBUG, "P2P: Unauthorize pending GO Neg peer "
5695 MACSTR, MAC2STR(peer));
5696 p2p_unauthorize(global->p2p, peer);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005697 found = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005698 }
5699
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005700 if (wpa_s->scan_res_handler == wpas_p2p_scan_res_join) {
5701 wpa_printf(MSG_DEBUG, "P2P: Stop pending scan for join");
5702 wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore;
5703 found = 1;
5704 }
5705
5706 if (wpa_s->pending_pd_before_join) {
5707 wpa_printf(MSG_DEBUG, "P2P: Stop pending PD before join");
5708 wpa_s->pending_pd_before_join = 0;
5709 found = 1;
5710 }
5711
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005712 wpas_p2p_stop_find(wpa_s);
5713
5714 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
5715 if (wpa_s == global->p2p_group_formation &&
5716 (wpa_s->p2p_in_provisioning ||
5717 wpa_s->parent->pending_interface_type ==
5718 WPA_IF_P2P_CLIENT)) {
5719 wpa_printf(MSG_DEBUG, "P2P: Interface %s in group "
5720 "formation found - cancelling",
5721 wpa_s->ifname);
5722 found = 1;
5723 eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
5724 wpa_s->parent, NULL);
Jouni Malinenadddfc42012-10-03 14:31:41 -07005725 if (wpa_s->p2p_in_provisioning) {
5726 wpas_group_formation_completed(wpa_s, 0);
5727 break;
5728 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005729 wpas_p2p_group_delete(wpa_s,
5730 P2P_GROUP_REMOVAL_REQUESTED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005731 break;
5732 }
5733 }
5734
5735 if (!found) {
5736 wpa_printf(MSG_DEBUG, "P2P: No ongoing group formation found");
5737 return -1;
5738 }
5739
5740 return 0;
5741}
5742
5743
5744void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
5745{
5746 if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
5747 return;
5748
5749 wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
5750 "being available anymore");
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005751 wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_UNAVAILABLE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005752}
5753
5754
5755void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
5756 int freq_24, int freq_5, int freq_overall)
5757{
5758 struct p2p_data *p2p = wpa_s->global->p2p;
5759 if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
5760 return;
5761 p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall);
5762}
5763
5764
5765int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr)
5766{
5767 u8 peer[ETH_ALEN];
5768 struct p2p_data *p2p = wpa_s->global->p2p;
5769
5770 if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
5771 return -1;
5772
5773 if (hwaddr_aton(addr, peer))
5774 return -1;
5775
5776 return p2p_unauthorize(p2p, peer);
5777}
5778
5779
5780/**
5781 * wpas_p2p_disconnect - Disconnect from a P2P Group
5782 * @wpa_s: Pointer to wpa_supplicant data
5783 * Returns: 0 on success, -1 on failure
5784 *
5785 * This can be used to disconnect from a group in which the local end is a P2P
5786 * Client or to end a P2P Group in case the local end is the Group Owner. If a
5787 * virtual network interface was created for this group, that interface will be
5788 * removed. Otherwise, only the configured P2P group network will be removed
5789 * from the interface.
5790 */
5791int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
5792{
5793
5794 if (wpa_s == NULL)
5795 return -1;
5796
Jouni Malinen2b89da82012-08-31 22:04:41 +03005797 return wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_REQUESTED) < 0 ?
5798 -1 : 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005799}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005800
5801
5802int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
5803{
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005804 int ret;
5805
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005806 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
5807 return 0;
5808
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005809 ret = p2p_in_progress(wpa_s->global->p2p);
5810 if (ret == 0) {
5811 /*
5812 * Check whether there is an ongoing WPS provisioning step (or
5813 * other parts of group formation) on another interface since
5814 * p2p_in_progress() does not report this to avoid issues for
5815 * scans during such provisioning step.
5816 */
5817 if (wpa_s->global->p2p_group_formation &&
5818 wpa_s->global->p2p_group_formation != wpa_s) {
5819 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Another interface (%s) "
5820 "in group formation",
5821 wpa_s->global->p2p_group_formation->ifname);
5822 ret = 1;
5823 }
5824 }
5825
5826 return ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005827}
5828
5829
5830void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
5831 struct wpa_ssid *ssid)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005832{
5833 if (wpa_s->p2p_in_provisioning && ssid->p2p_group &&
5834 eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
5835 wpa_s->parent, NULL) > 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07005836 /**
5837 * Remove the network by scheduling the group formation
5838 * timeout to happen immediately. The teardown code
5839 * needs to be scheduled to run asynch later so that we
5840 * don't delete data from under ourselves unexpectedly.
5841 * Calling wpas_p2p_group_formation_timeout directly
5842 * causes a series of crashes in WPS failure scenarios.
5843 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005844 wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to "
5845 "P2P group network getting removed");
Dmitry Shmidt04949592012-07-19 12:16:46 -07005846 eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
5847 wpa_s->parent, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005848 }
5849}
5850
5851
5852struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005853 const u8 *addr, const u8 *ssid,
5854 size_t ssid_len)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005855{
5856 struct wpa_ssid *s;
5857 size_t i;
5858
5859 for (s = wpa_s->conf->ssid; s; s = s->next) {
5860 if (s->disabled != 2)
5861 continue;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005862 if (ssid &&
5863 (ssid_len != s->ssid_len ||
5864 os_memcmp(ssid, s->ssid, ssid_len) != 0))
5865 continue;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005866 if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0)
5867 return s; /* peer is GO in the persistent group */
5868 if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL)
5869 continue;
5870 for (i = 0; i < s->num_p2p_clients; i++) {
5871 if (os_memcmp(s->p2p_client_list + i * ETH_ALEN,
5872 addr, ETH_ALEN) == 0)
5873 return s; /* peer is P2P client in persistent
5874 * group */
5875 }
5876 }
5877
5878 return NULL;
5879}
5880
5881
5882void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
5883 const u8 *addr)
5884{
5885 if (addr == NULL)
5886 return;
5887 wpas_p2p_add_persistent_group_client(wpa_s, addr);
5888}
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005889
Dmitry Shmidt04949592012-07-19 12:16:46 -07005890
5891static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
5892 int group_added)
5893{
5894 struct wpa_supplicant *group = wpa_s;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005895 if (wpa_s->global->p2p_group_formation)
5896 group = wpa_s->global->p2p_group_formation;
5897 wpa_s = wpa_s->parent;
5898 offchannel_send_action_done(wpa_s);
5899 if (group_added)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005900 wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005901 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
5902 wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
5903 wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
5904 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
5905 wpa_s->p2p_persistent_id,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005906 wpa_s->p2p_pd_before_go_neg,
5907 wpa_s->p2p_go_ht40);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005908}
5909
5910
5911int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
5912{
5913 if (!wpa_s->p2p_fallback_to_go_neg ||
5914 wpa_s->p2p_in_provisioning <= 5)
5915 return 0;
5916
5917 if (wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr) > 0)
5918 return 0; /* peer operating as a GO */
5919
5920 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
5921 "fallback to GO Negotiation");
5922 wpas_p2p_fallback_to_go_neg(wpa_s, 1);
5923
5924 return 1;
5925}
5926
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005927
5928unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
5929{
5930 const char *rn, *rn2;
5931 struct wpa_supplicant *ifs;
5932
5933 if (wpa_s->wpa_state > WPA_SCANNING) {
5934 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search delay due to "
5935 "concurrent operation",
5936 P2P_CONCURRENT_SEARCH_DELAY);
5937 return P2P_CONCURRENT_SEARCH_DELAY;
5938 }
5939
5940 if (!wpa_s->driver->get_radio_name)
5941 return 0;
5942 rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
5943 if (rn == NULL || rn[0] == '\0')
5944 return 0;
5945
5946 for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
5947 if (ifs == wpa_s || !ifs->driver->get_radio_name)
5948 continue;
5949
5950 rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
5951 if (!rn2 || os_strcmp(rn, rn2) != 0)
5952 continue;
5953 if (ifs->wpa_state > WPA_SCANNING) {
5954 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search "
5955 "delay due to concurrent operation on "
5956 "interface %s",
5957 P2P_CONCURRENT_SEARCH_DELAY, ifs->ifname);
5958 return P2P_CONCURRENT_SEARCH_DELAY;
5959 }
5960 }
5961
5962 return 0;
5963}
5964
Dmitry Shmidt37d4d6a2013-03-18 13:09:42 -07005965
5966void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
5967{
5968 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Station mode scan operation not "
5969 "pending anymore (sta_scan_pending=%d "
5970 "p2p_cb_on_scan_complete=%d)", wpa_s->sta_scan_pending,
5971 wpa_s->global->p2p_cb_on_scan_complete);
5972 wpa_s->sta_scan_pending = 0;
5973
5974 if (!wpa_s->global->p2p_cb_on_scan_complete)
5975 return;
5976 wpa_s->global->p2p_cb_on_scan_complete = 0;
5977
5978 if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
5979 return;
5980
5981 if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
5982 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
5983 "continued after successful connection");
5984 p2p_increase_search_delay(wpa_s->global->p2p,
5985 wpas_p2p_search_delay(wpa_s));
5986 }
5987}
5988
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005989#ifdef ANDROID_P2P
Dmitry Shmidt1cf45732013-04-29 17:36:45 -07005990static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx)
5991{
5992 struct wpa_supplicant *wpa_s = eloop_ctx;
5993
5994 wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - terminate group");
5995 wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
5996}
5997
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005998int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
5999 struct wpa_ssid *ssid)
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006000{
6001 struct wpa_supplicant *iface = NULL;
6002 struct p2p_data *p2p = wpa_s->global->p2p;
6003
6004 for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
Jeff Johnson12b1cd92012-10-07 19:34:24 -07006005 if ((iface->current_ssid) &&
6006 (iface->current_ssid->frequency != freq) &&
6007 ((iface->p2p_group_interface) ||
6008 (iface->current_ssid->p2p_group))) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006009
Jeff Johnson12b1cd92012-10-07 19:34:24 -07006010 if ((iface->p2p_group_interface == P2P_GROUP_INTERFACE_GO) ||
6011 (iface->current_ssid->mode == WPAS_MODE_P2P_GO)) {
6012 /* Try to see whether we can move the GO. If it
6013 * is not possible, remove the GO interface
6014 */
6015 if (wpa_drv_switch_channel(iface, freq) == 0) {
6016 wpa_printf(MSG_ERROR, "P2P: GO Moved to freq(%d)", freq);
6017 iface->current_ssid->frequency = freq;
6018 continue;
6019 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006020 }
6021
6022 /* If GO cannot be moved or if the conflicting interface is a
6023 * P2P Client, remove the interface depending up on the connection
6024 * priority */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006025 if(!wpas_is_p2p_prioritized(iface)) {
Dmitry Shmidtf4f5db32012-09-11 14:36:56 -07006026 /* STA connection has priority over existing
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006027 * P2P connection. So remove the interface */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006028 wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
Dmitry Shmidt687922c2012-03-26 14:02:32 -07006029 "concurrent mode frequency conflict");
Dmitry Shmidt1cf45732013-04-29 17:36:45 -07006030 eloop_register_timeout(0, 0, wpas_p2p_group_freq_conflict,
6031 iface, NULL);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006032 /* If connection in progress is p2p connection, do not proceed for the connection */
6033 if (wpa_s == iface)
6034 return -1;
6035 else
6036 /* If connection in progress is STA connection, proceed for the connection */
6037 return 0;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006038 } else {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006039 /* P2p connection has priority, disable the STA network*/
6040 wpa_supplicant_disable_network(wpa_s->global->ifaces, ssid);
6041 wpa_msg(wpa_s->global->ifaces, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
6042 " id=%d", ssid->id);
6043 os_memset(wpa_s->global->ifaces->pending_bssid, 0, ETH_ALEN);
6044 if (wpa_s == iface) {
6045 /* p2p connection is in progress, continue connecting...*/
6046 return 0;
6047 }
6048 else {
6049 /* STA connection is in progress, do not allow to continue */
6050 return -1;
6051 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006052 }
6053 }
6054 }
6055 return 0;
6056}
6057#endif