P2P: Report dev_found event (if not yet done) from GO Neg Req RX
[mech_eap.git] / src / p2p / p2p_go_neg.c
index f23cff6..a32cfac 100644 (file)
@@ -217,6 +217,8 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
        }
 
        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",
@@ -592,12 +594,32 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
        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) {
                /*
@@ -614,7 +636,11 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
        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;
@@ -701,6 +727,28 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
                        }
                        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;
@@ -1026,6 +1074,17 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
                }
                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;
@@ -1097,6 +1156,7 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
 
        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;