Handle NULL return from os_zalloc() in sta_track_add()
[mech_eap.git] / src / p2p / p2p_invitation.c
index a36898e..bbba001 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "p2p_i.h"
 #include "p2p.h"
 
@@ -45,6 +46,9 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
                extra = wpabuf_len(wfd_ie);
 #endif /* CONFIG_WIFI_DISPLAY */
 
+       if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
+               extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
+
        buf = wpabuf_alloc(1000 + extra);
        if (buf == NULL)
                return NULL;
@@ -81,11 +85,17 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
        p2p_buf_add_device_info(buf, p2p, peer);
        p2p_buf_update_ie_hdr(buf, len);
 
+       p2p_buf_add_pref_channel_list(buf, p2p->pref_freq_list,
+                                     p2p->num_pref_freq);
+
 #ifdef CONFIG_WIFI_DISPLAY
        if (wfd_ie)
                wpabuf_put_buf(buf, wfd_ie);
 #endif /* CONFIG_WIFI_DISPLAY */
 
+       if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
+               wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
+
        if (dev_pw_id >= 0) {
                /* WSC IE in Invitation Request for NFC static handover */
                p2p_build_wps_ie(p2p, buf, dev_pw_id, 0);
@@ -127,6 +137,9 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
                extra = wpabuf_len(wfd_ie);
 #endif /* CONFIG_WIFI_DISPLAY */
 
+       if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP])
+               extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP]);
+
        buf = wpabuf_alloc(1000 + extra);
        if (buf == NULL)
                return NULL;
@@ -151,6 +164,9 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
                wpabuf_put_buf(buf, wfd_ie);
 #endif /* CONFIG_WIFI_DISPLAY */
 
+       if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP])
+               wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP]);
+
        return buf;
 }
 
@@ -167,7 +183,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
        u8 group_bssid[ETH_ALEN], *bssid;
        int op_freq = 0;
        u8 reg_class = 0, channel = 0;
-       struct p2p_channels intersection, *channels = NULL;
+       struct p2p_channels all_channels, intersection, *channels = NULL;
        int persistent;
 
        os_memset(group_bssid, 0, sizeof(group_bssid));
@@ -219,7 +235,10 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
                persistent = 1;
        }
 
-       if (p2p_peer_channels_check(p2p, &p2p->cfg->channels, dev,
+       p2p_channels_union(&p2p->cfg->channels, &p2p->cfg->cli_channels,
+                          &all_channels);
+
+       if (p2p_peer_channels_check(p2p, &all_channels, dev,
                                    msg.channel_list, msg.channel_list_len) <
            0) {
                p2p_dbg(p2p, "No common channels found");
@@ -228,8 +247,9 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
        }
 
        p2p_channels_dump(p2p, "own channels", &p2p->cfg->channels);
+       p2p_channels_dump(p2p, "own client channels", &all_channels);
        p2p_channels_dump(p2p, "peer channels", &dev->channels);
-       p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+       p2p_channels_intersect(&all_channels, &dev->channels,
                               &intersection);
        p2p_channels_dump(p2p, "intersection", &intersection);
 
@@ -241,6 +261,17 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
                        msg.dev_password_id_present ? msg.dev_password_id : -1);
        }
 
+       if (go) {
+               p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+                                      &intersection);
+               p2p_channels_dump(p2p, "intersection(GO)", &intersection);
+               if (intersection.reg_classes == 0) {
+                       p2p_dbg(p2p, "No common channels found (GO)");
+                       status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+                       goto fail;
+               }
+       }
+
        if (op_freq) {
                p2p_dbg(p2p, "Invitation processing forced frequency %d MHz",
                        op_freq);
@@ -253,7 +284,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
 
                if (!p2p_channels_includes(&intersection, reg_class, channel))
                {
-                       p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction",
+                       p2p_dbg(p2p, "forced freq %d MHz not in the supported channels intersection",
                                op_freq);
                        status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
                        goto fail;
@@ -315,6 +346,12 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
                        p2p_reselect_channel(p2p, &intersection);
                }
 
+               /*
+                * Use the driver preferred frequency list extension if
+                * supported.
+                */
+               p2p_check_pref_chan(p2p, go, dev, &msg);
+
                op_freq = p2p_channel_to_freq(p2p->op_reg_class,
                                              p2p->op_channel);
                if (op_freq < 0) {
@@ -365,7 +402,7 @@ fail:
        } else
                p2p->inv_group_bssid_ptr = NULL;
        if (msg.group_id) {
-               if (msg.group_id_len - ETH_ALEN <= 32) {
+               if (msg.group_id_len - ETH_ALEN <= SSID_MAX_LEN) {
                        os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN,
                                  msg.group_id_len - ETH_ALEN);
                        p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN;
@@ -381,7 +418,7 @@ fail:
        p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE;
        if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
                            p2p->cfg->dev_addr,
-                           wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
+                           wpabuf_head(resp), wpabuf_len(resp), 50) < 0) {
                p2p_dbg(p2p, "Failed to send Action frame");
        }
 
@@ -405,25 +442,68 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
        if (dev == NULL) {
                p2p_dbg(p2p, "Ignore Invitation Response from unknown peer "
                        MACSTR, MAC2STR(sa));
+               p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
                return;
        }
 
        if (dev != p2p->invite_peer) {
                p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer "
                        MACSTR, MAC2STR(sa));
+               p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
                return;
        }
 
-       if (p2p_parse(data, len, &msg))
+       if (p2p_parse(data, len, &msg)) {
+               p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
                return;
+       }
 
        if (!msg.status) {
                p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from "
                        MACSTR, MAC2STR(sa));
                p2p_parse_free(&msg);
+               p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+               return;
+       }
+
+       /*
+        * We should not really receive a replayed response twice since
+        * duplicate frames are supposed to be dropped. However, not all drivers
+        * do that for pre-association frames. We did not use to verify dialog
+        * token matches for invitation response frames, but that check can be
+        * safely used to drop a replayed response to the previous Invitation
+        * Request in case the suggested operating channel was changed. This
+        * allows a duplicated reject frame to be dropped with the assumption
+        * that the real response follows after it.
+        */
+       if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+           p2p->retry_invite_req_sent &&
+           msg.dialog_token != dev->dialog_token) {
+               p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
+                       msg.dialog_token, dev->dialog_token);
+               p2p_parse_free(&msg);
                return;
        }
 
+       if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+           p2p->retry_invite_req &&
+           p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class,
+                                     &p2p->op_channel) == 0) {
+               p2p->retry_invite_req = 0;
+               p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+               p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+               p2p_set_state(p2p, P2P_INVITE);
+               p2p_dbg(p2p, "Resend Invitation Request setting op_class %u channel %u as operating channel",
+                       p2p->op_reg_class, p2p->op_channel);
+               p2p->retry_invite_req_sent = 1;
+               p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
+                               p2p->invite_dev_pw_id);
+               p2p_parse_free(&msg);
+               return;
+       }
+       p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+       p2p->retry_invite_req = 0;
+
        if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) {
                p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
                        MACSTR, MAC2STR(sa));
@@ -463,6 +543,12 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
                                peer_oper_freq = 0;
                }
 
+               /*
+                * Use the driver preferred frequency list extension if
+                * supported.
+                */
+               p2p_check_pref_chan(p2p, 0, dev, &msg);
+
                p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
                                            msg.group_bssid, channels, sa,
                                            freq, peer_oper_freq);
@@ -585,6 +671,9 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
                        dev_pw_id);
        }
        p2p->invite_dev_pw_id = dev_pw_id;
+       p2p->retry_invite_req = role == P2P_INVITE_ROLE_GO &&
+               persistent_group && !force_freq;
+       p2p->retry_invite_req_sent = 0;
 
        dev = p2p_get_device(p2p, peer);
        if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 &&