p2p_pd.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. /*
  2. * Wi-Fi Direct - P2P provision discovery
  3. * Copyright (c) 2009-2010, Atheros Communications
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include "includes.h"
  9. #include "common.h"
  10. #include "common/ieee802_11_defs.h"
  11. #include "common/wpa_ctrl.h"
  12. #include "wps/wps_defs.h"
  13. #include "p2p_i.h"
  14. #include "p2p.h"
  15. /*
  16. * Number of retries to attempt for provision discovery requests
  17. * in case the peer is not listening.
  18. */
  19. #define MAX_PROV_DISC_REQ_RETRIES 120
  20. static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
  21. u16 config_methods)
  22. {
  23. u8 *len;
  24. wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
  25. len = wpabuf_put(buf, 1);
  26. wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
  27. /* Config Methods */
  28. wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
  29. wpabuf_put_be16(buf, 2);
  30. wpabuf_put_be16(buf, config_methods);
  31. p2p_buf_update_ie_hdr(buf, len);
  32. }
  33. static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
  34. u8 dialog_token,
  35. u16 config_methods,
  36. struct p2p_device *go)
  37. {
  38. struct wpabuf *buf;
  39. u8 *len;
  40. size_t extra = 0;
  41. #ifdef CONFIG_WIFI_DISPLAY
  42. if (p2p->wfd_ie_prov_disc_req)
  43. extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
  44. #endif /* CONFIG_WIFI_DISPLAY */
  45. if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
  46. extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
  47. buf = wpabuf_alloc(1000 + extra);
  48. if (buf == NULL)
  49. return NULL;
  50. p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
  51. len = p2p_buf_add_ie_hdr(buf);
  52. p2p_buf_add_capability(buf, p2p->dev_capab &
  53. ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
  54. p2p_buf_add_device_info(buf, p2p, NULL);
  55. if (go) {
  56. p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
  57. go->oper_ssid, go->oper_ssid_len);
  58. }
  59. p2p_buf_update_ie_hdr(buf, len);
  60. /* WPS IE with Config Methods attribute */
  61. p2p_build_wps_ie_config_methods(buf, config_methods);
  62. #ifdef CONFIG_WIFI_DISPLAY
  63. if (p2p->wfd_ie_prov_disc_req)
  64. wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
  65. #endif /* CONFIG_WIFI_DISPLAY */
  66. if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
  67. wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
  68. return buf;
  69. }
  70. static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
  71. u8 dialog_token,
  72. u16 config_methods,
  73. const u8 *group_id,
  74. size_t group_id_len)
  75. {
  76. struct wpabuf *buf;
  77. size_t extra = 0;
  78. #ifdef CONFIG_WIFI_DISPLAY
  79. struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
  80. if (wfd_ie && group_id) {
  81. size_t i;
  82. for (i = 0; i < p2p->num_groups; i++) {
  83. struct p2p_group *g = p2p->groups[i];
  84. struct wpabuf *ie;
  85. if (!p2p_group_is_group_id_match(g, group_id,
  86. group_id_len))
  87. continue;
  88. ie = p2p_group_get_wfd_ie(g);
  89. if (ie) {
  90. wfd_ie = ie;
  91. break;
  92. }
  93. }
  94. }
  95. if (wfd_ie)
  96. extra = wpabuf_len(wfd_ie);
  97. #endif /* CONFIG_WIFI_DISPLAY */
  98. if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
  99. extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
  100. buf = wpabuf_alloc(100 + extra);
  101. if (buf == NULL)
  102. return NULL;
  103. p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
  104. /* WPS IE with Config Methods attribute */
  105. p2p_build_wps_ie_config_methods(buf, config_methods);
  106. #ifdef CONFIG_WIFI_DISPLAY
  107. if (wfd_ie)
  108. wpabuf_put_buf(buf, wfd_ie);
  109. #endif /* CONFIG_WIFI_DISPLAY */
  110. if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
  111. wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
  112. return buf;
  113. }
  114. void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
  115. const u8 *data, size_t len, int rx_freq)
  116. {
  117. struct p2p_message msg;
  118. struct p2p_device *dev;
  119. int freq;
  120. int reject = 1;
  121. struct wpabuf *resp;
  122. if (p2p_parse(data, len, &msg))
  123. return;
  124. p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
  125. " with config methods 0x%x (freq=%d)",
  126. MAC2STR(sa), msg.wps_config_methods, rx_freq);
  127. dev = p2p_get_device(p2p, sa);
  128. if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
  129. p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
  130. MACSTR, MAC2STR(sa));
  131. if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
  132. 0)) {
  133. p2p_dbg(p2p, "Provision Discovery Request add device failed "
  134. MACSTR, MAC2STR(sa));
  135. }
  136. } else if (msg.wfd_subelems) {
  137. wpabuf_free(dev->info.wfd_subelems);
  138. dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
  139. }
  140. if (!(msg.wps_config_methods &
  141. (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
  142. WPS_CONFIG_PUSHBUTTON))) {
  143. p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
  144. goto out;
  145. }
  146. if (msg.group_id) {
  147. size_t i;
  148. for (i = 0; i < p2p->num_groups; i++) {
  149. if (p2p_group_is_group_id_match(p2p->groups[i],
  150. msg.group_id,
  151. msg.group_id_len))
  152. break;
  153. }
  154. if (i == p2p->num_groups) {
  155. p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject");
  156. goto out;
  157. }
  158. }
  159. if (dev)
  160. dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
  161. P2P_DEV_PD_PEER_KEYPAD);
  162. if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
  163. p2p_dbg(p2p, "Peer " MACSTR
  164. " requested us to show a PIN on display", MAC2STR(sa));
  165. if (dev)
  166. dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
  167. } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
  168. p2p_dbg(p2p, "Peer " MACSTR
  169. " requested us to write its PIN using keypad",
  170. MAC2STR(sa));
  171. if (dev)
  172. dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
  173. }
  174. reject = 0;
  175. out:
  176. resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
  177. reject ? 0 : msg.wps_config_methods,
  178. msg.group_id, msg.group_id_len);
  179. if (resp == NULL) {
  180. p2p_parse_free(&msg);
  181. return;
  182. }
  183. p2p_dbg(p2p, "Sending Provision Discovery Response");
  184. if (rx_freq > 0)
  185. freq = rx_freq;
  186. else
  187. freq = p2p_channel_to_freq(p2p->cfg->reg_class,
  188. p2p->cfg->channel);
  189. if (freq < 0) {
  190. p2p_dbg(p2p, "Unknown regulatory class/channel");
  191. wpabuf_free(resp);
  192. p2p_parse_free(&msg);
  193. return;
  194. }
  195. p2p->pending_action_state = P2P_NO_PENDING_ACTION;
  196. if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
  197. p2p->cfg->dev_addr,
  198. wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
  199. p2p_dbg(p2p, "Failed to send Action frame");
  200. } else
  201. p2p->send_action_in_progress = 1;
  202. wpabuf_free(resp);
  203. if (!reject && p2p->cfg->prov_disc_req) {
  204. const u8 *dev_addr = sa;
  205. if (msg.p2p_device_addr)
  206. dev_addr = msg.p2p_device_addr;
  207. p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
  208. msg.wps_config_methods,
  209. dev_addr, msg.pri_dev_type,
  210. msg.device_name, msg.config_methods,
  211. msg.capability ? msg.capability[0] : 0,
  212. msg.capability ? msg.capability[1] :
  213. 0,
  214. msg.group_id, msg.group_id_len);
  215. }
  216. p2p_parse_free(&msg);
  217. }
  218. void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
  219. const u8 *data, size_t len)
  220. {
  221. struct p2p_message msg;
  222. struct p2p_device *dev;
  223. u16 report_config_methods = 0, req_config_methods;
  224. int success = 0;
  225. if (p2p_parse(data, len, &msg))
  226. return;
  227. p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
  228. " with config methods 0x%x",
  229. MAC2STR(sa), msg.wps_config_methods);
  230. dev = p2p_get_device(p2p, sa);
  231. if (dev == NULL || !dev->req_config_methods) {
  232. p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
  233. " with no pending request", MAC2STR(sa));
  234. p2p_parse_free(&msg);
  235. return;
  236. }
  237. if (dev->dialog_token != msg.dialog_token) {
  238. p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
  239. msg.dialog_token, dev->dialog_token);
  240. p2p_parse_free(&msg);
  241. return;
  242. }
  243. if (p2p->pending_action_state == P2P_PENDING_PD) {
  244. os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
  245. p2p->pending_action_state = P2P_NO_PENDING_ACTION;
  246. }
  247. /*
  248. * Use a local copy of the requested config methods since
  249. * p2p_reset_pending_pd() can clear this in the peer entry.
  250. */
  251. req_config_methods = dev->req_config_methods;
  252. /*
  253. * If the response is from the peer to whom a user initiated request
  254. * was sent earlier, we reset that state info here.
  255. */
  256. if (p2p->user_initiated_pd &&
  257. os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
  258. p2p_reset_pending_pd(p2p);
  259. if (msg.wps_config_methods != req_config_methods) {
  260. p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
  261. msg.wps_config_methods, req_config_methods);
  262. if (p2p->cfg->prov_disc_fail)
  263. p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
  264. P2P_PROV_DISC_REJECTED);
  265. p2p_parse_free(&msg);
  266. goto out;
  267. }
  268. report_config_methods = req_config_methods;
  269. dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
  270. P2P_DEV_PD_PEER_KEYPAD);
  271. if (req_config_methods & WPS_CONFIG_DISPLAY) {
  272. p2p_dbg(p2p, "Peer " MACSTR
  273. " accepted to show a PIN on display", MAC2STR(sa));
  274. dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
  275. } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
  276. p2p_dbg(p2p, "Peer " MACSTR
  277. " accepted to write our PIN using keypad",
  278. MAC2STR(sa));
  279. dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
  280. }
  281. /* Store the provisioning info */
  282. dev->wps_prov_info = msg.wps_config_methods;
  283. p2p_parse_free(&msg);
  284. success = 1;
  285. out:
  286. dev->req_config_methods = 0;
  287. p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
  288. if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
  289. p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with "
  290. MACSTR, MAC2STR(dev->info.p2p_device_addr));
  291. dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
  292. p2p_connect_send(p2p, dev);
  293. return;
  294. }
  295. if (success && p2p->cfg->prov_disc_resp)
  296. p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
  297. report_config_methods);
  298. if (p2p->state == P2P_PD_DURING_FIND) {
  299. p2p_clear_timeout(p2p);
  300. p2p_continue_find(p2p);
  301. }
  302. }
  303. int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
  304. int join, int force_freq)
  305. {
  306. struct wpabuf *req;
  307. int freq;
  308. if (force_freq > 0)
  309. freq = force_freq;
  310. else
  311. freq = dev->listen_freq > 0 ? dev->listen_freq :
  312. dev->oper_freq;
  313. if (freq <= 0) {
  314. p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
  315. MACSTR " to send Provision Discovery Request",
  316. MAC2STR(dev->info.p2p_device_addr));
  317. return -1;
  318. }
  319. if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
  320. if (!(dev->info.dev_capab &
  321. P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
  322. p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR
  323. " that is in a group and is not discoverable",
  324. MAC2STR(dev->info.p2p_device_addr));
  325. return -1;
  326. }
  327. /* TODO: use device discoverability request through GO */
  328. }
  329. req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
  330. dev->req_config_methods,
  331. join ? dev : NULL);
  332. if (req == NULL)
  333. return -1;
  334. if (p2p->state != P2P_IDLE)
  335. p2p_stop_listen_for_freq(p2p, freq);
  336. p2p->pending_action_state = P2P_PENDING_PD;
  337. if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
  338. p2p->cfg->dev_addr, dev->info.p2p_device_addr,
  339. wpabuf_head(req), wpabuf_len(req), 200) < 0) {
  340. p2p_dbg(p2p, "Failed to send Action frame");
  341. wpabuf_free(req);
  342. return -1;
  343. }
  344. os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
  345. wpabuf_free(req);
  346. return 0;
  347. }
  348. int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
  349. u16 config_methods, int join, int force_freq,
  350. int user_initiated_pd)
  351. {
  352. struct p2p_device *dev;
  353. dev = p2p_get_device(p2p, peer_addr);
  354. if (dev == NULL)
  355. dev = p2p_get_device_interface(p2p, peer_addr);
  356. if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
  357. p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
  358. " not yet known", MAC2STR(peer_addr));
  359. return -1;
  360. }
  361. p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
  362. " (config methods 0x%x)",
  363. MAC2STR(peer_addr), config_methods);
  364. if (config_methods == 0)
  365. return -1;
  366. /* Reset provisioning info */
  367. dev->wps_prov_info = 0;
  368. dev->req_config_methods = config_methods;
  369. if (join)
  370. dev->flags |= P2P_DEV_PD_FOR_JOIN;
  371. else
  372. dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
  373. if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
  374. p2p->state != P2P_LISTEN_ONLY) {
  375. p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
  376. MACSTR " (config methods 0x%x)",
  377. MAC2STR(peer_addr), config_methods);
  378. return 0;
  379. }
  380. p2p->user_initiated_pd = user_initiated_pd;
  381. p2p->pd_force_freq = force_freq;
  382. if (p2p->user_initiated_pd)
  383. p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
  384. /*
  385. * Assign dialog token here to use the same value in each retry within
  386. * the same PD exchange.
  387. */
  388. dev->dialog_token++;
  389. if (dev->dialog_token == 0)
  390. dev->dialog_token = 1;
  391. return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
  392. }
  393. void p2p_reset_pending_pd(struct p2p_data *p2p)
  394. {
  395. struct p2p_device *dev;
  396. dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
  397. if (os_memcmp(p2p->pending_pd_devaddr,
  398. dev->info.p2p_device_addr, ETH_ALEN))
  399. continue;
  400. if (!dev->req_config_methods)
  401. continue;
  402. if (dev->flags & P2P_DEV_PD_FOR_JOIN)
  403. continue;
  404. /* Reset the config methods of the device */
  405. dev->req_config_methods = 0;
  406. }
  407. p2p->user_initiated_pd = 0;
  408. os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
  409. p2p->pd_retries = 0;
  410. p2p->pd_force_freq = 0;
  411. }