return DEV_PW_USER_SPECIFIED;
case WPS_PBC:
return DEV_PW_PUSHBUTTON;
+ case WPS_NFC:
+ return DEV_PW_NFC_CONNECTION_HANDOVER;
default:
return DEV_PW_DEFAULT;
}
return "Keypad";
case WPS_PBC:
return "PBC";
+ case WPS_NFC:
+ return "NFC";
default:
return "??";
}
u8 *len;
u8 group_capab;
size_t extra = 0;
+ u16 pw_id;
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
- if (p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method),
- 0) < 0) {
+ pw_id = p2p_wps_method_pw_id(peer->wps_method);
+ if (peer->oob_pw_id)
+ pw_id = peer->oob_pw_id;
+ if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request");
wpabuf_free(buf);
return NULL;
}
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+ if (dev->oob_go_neg_freq > 0)
+ freq = dev->oob_go_neg_freq;
if (freq <= 0) {
p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
MACSTR " to send GO Negotiation Request",
u8 *len;
u8 group_capab;
size_t extra = 0;
+ u16 pw_id;
p2p_dbg(p2p, "Building GO Negotiation Response");
p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
- if (p2p_build_wps_ie(p2p, buf,
- p2p_wps_method_pw_id(peer ? peer->wps_method :
- WPS_NOT_READY), 0) < 0) {
+ pw_id = p2p_wps_method_pw_id(peer ? peer->wps_method : WPS_NOT_READY);
+ if (peer && peer->oob_pw_id)
+ pw_id = peer->oob_pw_id;
+ if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response");
wpabuf_free(buf);
return NULL;
if (msg.status && *msg.status) {
p2p_dbg(p2p, "Unexpected Status attribute (%d) in GO Negotiation Request",
*msg.status);
+ if (dev && p2p->go_neg_peer == dev &&
+ *msg.status == P2P_SC_FAIL_REJECTED_BY_USER) {
+ /*
+ * This mechanism for using Status attribute in GO
+ * Negotiation Request is not compliant with the P2P
+ * specification, but some deployed devices use it to
+ * indicate rejection of GO Negotiation in a case where
+ * they have sent out GO Negotiation Response with
+ * status 1. The P2P specification explicitly disallows
+ * this. To avoid unnecessary interoperability issues
+ * and extra frames, mark the pending negotiation as
+ * failed and do not reply to this GO Negotiation
+ * Request frame.
+ */
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p_go_neg_failed(p2p, dev, *msg.status);
+ p2p_parse_free(&msg);
+ return;
+ }
goto fail;
}
if (dev == NULL)
dev = p2p_add_dev_from_go_neg_req(p2p, sa, &msg);
- else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY)
+ else if ((dev->flags & P2P_DEV_PROBE_REQ_ONLY) ||
+ !(dev->flags & P2P_DEV_REPORTED))
p2p_add_dev_info(p2p, sa, dev, &msg);
+ else if (!dev->listen_freq && !dev->oper_freq) {
+ /*
+ * This may happen if the peer entry was added based on PD
+ * Request and no Probe Request/Response frame has been received
+ * from this peer (or that information has timed out).
+ */
+ p2p_dbg(p2p, "Update peer " MACSTR
+ " based on GO Neg Req since listen/oper freq not known",
+ MAC2STR(dev->info.p2p_device_addr));
+ p2p_add_dev_info(p2p, sa, dev, &msg);
+ }
+
if (dev && dev->flags & P2P_DEV_USER_REJECTED) {
p2p_dbg(p2p, "User has rejected this peer");
status = P2P_SC_FAIL_REJECTED_BY_USER;
- } else if (dev == NULL || dev->wps_method == WPS_NOT_READY) {
+ } else if (dev == NULL ||
+ (dev->wps_method == WPS_NOT_READY &&
+ (p2p->authorized_oob_dev_pw_id == 0 ||
+ p2p->authorized_oob_dev_pw_id !=
+ msg.dev_password_id))) {
p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
}
break;
default:
+ if (msg.dev_password_id &&
+ msg.dev_password_id == dev->oob_pw_id) {
+ p2p_dbg(p2p, "Peer using NFC");
+ if (dev->wps_method != WPS_NFC) {
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(
+ dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ }
+#ifdef CONFIG_WPS_NFC
+ if (p2p->authorized_oob_dev_pw_id &&
+ msg.dev_password_id ==
+ p2p->authorized_oob_dev_pw_id) {
+ p2p_dbg(p2p, "Using static handover with our device password from NFC Tag");
+ dev->wps_method = WPS_NFC;
+ dev->oob_pw_id = p2p->authorized_oob_dev_pw_id;
+ break;
+ }
+#endif /* CONFIG_WPS_NFC */
p2p_dbg(p2p, "Unsupported Device Password ID %d",
msg.dev_password_id);
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
}
break;
default:
+ if (msg.dev_password_id &&
+ msg.dev_password_id == dev->oob_pw_id) {
+ p2p_dbg(p2p, "Peer using NFC");
+ if (dev->wps_method != WPS_NFC) {
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ }
p2p_dbg(p2p, "Unsupported Device Password ID %d",
msg.dev_password_id);
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
else
freq = dev->listen_freq;
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
- wpabuf_head(conf), wpabuf_len(conf), 0) < 0) {
+ wpabuf_head(conf), wpabuf_len(conf), 200) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
p2p_go_neg_failed(p2p, dev, -1);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
p2p_dbg(p2p, "Was not expecting GO Negotiation Confirm - ignore");
+ p2p_parse_free(&msg);
return;
}
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;