Cumulative patch from commit f5728d0a82d5c5fb5347e41ce761fdf4a79772ec am: 58d12adcdf
am: f857d02690
Change-Id: I1b1b69290d7a868e424d8c0e162678288ee47191
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 62bef18..4e7b58e 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -2254,6 +2254,34 @@
}
+static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
+ size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) iface->drv_flags);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (iface->drv_flags & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply,
int reply_size,
@@ -2510,6 +2538,9 @@
} else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
reply_len = -1;
+ } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+ reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
+ reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index ff133f6..5c1f297 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1218,6 +1218,13 @@
}
+static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -1283,6 +1290,7 @@
{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor },
{ "req_lci", hostapd_cli_cmd_req_lci },
{ "req_range", hostapd_cli_cmd_req_range },
+ { "driver_flags", hostapd_cli_cmd_driver_flags },
{ NULL, NULL }
};
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 98601a8..11f12f9 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1385,6 +1385,9 @@
return 0;
}
+ if (TEST_FAIL())
+ return -1;
+
for (i = 0; i < AID_WORDS; i++) {
if (hapd->sta_aid[i] == (u32) -1)
continue;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 5d4d0c8..cf3fbb1 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -80,6 +80,7 @@
enum mesh_plink_state plink_state;
u16 peer_lid;
u16 my_lid;
+ u16 peer_aid;
u16 mpm_close_reason;
int mpm_retries;
u8 my_nonce[WPA_NONCE_LEN];
diff --git a/src/common/defs.h b/src/common/defs.h
index 6ef929c..4f56794 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -320,13 +320,13 @@
#define EAP_MAX_METHODS 8
enum mesh_plink_state {
- PLINK_LISTEN = 1,
- PLINK_OPEN_SENT,
- PLINK_OPEN_RCVD,
+ PLINK_IDLE = 1,
+ PLINK_OPN_SNT,
+ PLINK_OPN_RCVD,
PLINK_CNF_RCVD,
PLINK_ESTAB,
PLINK_HOLDING,
- PLINK_BLOCKED,
+ PLINK_BLOCKED, /* not defined in the IEEE 802.11 standard */
};
enum set_band {
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index bac87ed..912d1e1 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -89,6 +89,32 @@
* @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: Event used by driver,
* which supports DFS offloading, to indicate a radar pattern has been
* detected. The channel is now unusable.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START: Command used to
+ * start the P2P Listen offload function in device and pass the listen
+ * channel, period, interval, count, device types, and vendor specific
+ * information elements to the device driver and firmware.
+ * Uses the attributes defines in
+ * enum qca_wlan_vendor_attr_p2p_listen_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: Command/event used to
+ * indicate stop request/response of the P2P Listen offload function in
+ * device. As an event, it indicates either the feature stopped after it
+ * was already running or feature has actually failed to start. Uses the
+ * attributes defines in enum qca_wlan_vendor_attr_p2p_listen_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH: After AP starts
+ * beaconing, this sub command provides the driver, the frequencies on the
+ * 5 GHz band to check for any radar activity. Driver selects one channel
+ * from this priority list provided through
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST and starts
+ * to check for radar activity on it. If no radar activity is detected
+ * during the channel availability check period, driver internally switches
+ * to the selected frequency of operation. If the frequency is zero, driver
+ * internally selects a channel. The status of this conditional switch is
+ * indicated through an event using the same sub command through
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS. Attributes are
+ * listed in qca_wlan_vendor_attr_sap_conditional_chan_switch.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -171,6 +197,9 @@
QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
QCA_NL80211_VENDOR_SUBCMD_WISA = 120,
/* 121 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START = 122,
+ QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP = 123,
+ QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH = 124,
};
@@ -227,6 +256,43 @@
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST - 1
};
+enum qca_wlan_vendor_attr_p2p_listen_offload {
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INVALID = 0,
+ /* A 32-bit unsigned value; the P2P listen frequency (MHz); must be one
+ * of the social channels.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
+ /* A 32-bit unsigned value; the P2P listen offload period (ms).
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
+ /* A 32-bit unsigned value; the P2P listen interval duration (ms).
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
+ /* A 32-bit unsigned value; number of interval times the firmware needs
+ * to run the offloaded P2P listen operation before it stops.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
+ /* An array of arbitrary binary data with one or more 8-byte values.
+ * The device types include both primary and secondary device types.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
+ /* An array of unsigned 8-bit characters; vendor information elements.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
+ /* A 32-bit unsigned value; a control flag to indicate whether listen
+ * results need to be flushed to wpa_supplicant.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG,
+ /* A 8-bit unsigned value; reason code for P2P listen offload stop
+ * event.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX =
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1
+};
+
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
@@ -265,12 +331,19 @@
* band selection based on channel selection results.
* @QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS: Device supports
* simultaneous off-channel operations.
+ * @QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD: Device supports P2P
+ * Listen offload; a mechanism where the station's firmware takes care of
+ * responding to incoming Probe Request frames received from other P2P
+ * Devices whilst in Listen state, rather than having the user space
+ * wpa_supplicant do it. Information from received P2P requests are
+ * forwarded from firmware to host whenever the host processor wakes up.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1,
QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS = 2,
+ QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD = 3,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -576,6 +649,25 @@
/* 8-bit unsigned value to configure the maximum RX MPDU for
* aggregation. */
QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION,
+ /* 8-bit unsigned value to configure the Non aggregrate/11g sw
+ * retry threshold (0 disable, 31 max). */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY,
+ /* 8-bit unsigned value to configure the aggregrate sw
+ * retry threshold (0 disable, 31 max). */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY,
+ /* 8-bit unsigned value to configure the MGMT frame
+ * retry threshold (0 disable, 31 max). */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY,
+ /* 8-bit unsigned value to configure the CTRL frame
+ * retry threshold (0 disable, 31 max). */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY,
+ /* 8-bit unsigned value to configure the propagation delay for
+ * 2G/5G band (0~63, units in us) */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY,
+ /* Unsigned 32-bit value to configure the number of unicast TX fail
+ * packet count. The peer is disconnected once this threshold is
+ * reached. */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT,
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
@@ -602,4 +694,23 @@
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_vendor_attr_sap_conditional_chan_switch - Parameters for AP
+ * conditional channel switch
+ */
+enum qca_wlan_vendor_attr_sap_conditional_chan_switch {
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_INVALID = 0,
+ /* Priority based frequency list (an array of u32 values in host byte
+ * order) */
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST = 1,
+ /* Status of the conditional switch (u32).
+ * 0: Success, Non-zero: Failure
+ */
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS = 2,
+
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX =
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index d6295b2..299b8bb 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1184,6 +1184,8 @@
"WPA2-PSK" : "WPA-PSK";
case WPA_KEY_MGMT_NONE:
return "NONE";
+ case WPA_KEY_MGMT_WPA_NONE:
+ return "WPA-NONE";
case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
return "IEEE 802.1X (no WPA)";
#ifdef CONFIG_IEEE80211R
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index df26c7b..4dcba81 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -228,6 +228,11 @@
/* parameters: <addr> <result> */
#define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
+#define RX_ANQP "RX-ANQP "
+#define RX_HS20_ANQP "RX-HS20-ANQP "
+#define RX_HS20_ANQP_ICON "RX-HS20-ANQP-ICON "
+#define RX_HS20_ICON "RX-HS20-ICON "
+
#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
@@ -271,6 +276,9 @@
#define AP_CSA_FINISHED "AP-CSA-FINISHED "
+#define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED "
+#define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON "
+
/* BSS Transition Management Response frame received */
#define BSS_TM_RESP "BSS-TM-RESP "
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index fde154f..7f33686 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -754,7 +754,7 @@
priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
- if (!priv_key || !pub_key || DH_set0_key(dh, pub_key, priv_key) != 0)
+ if (!priv_key || !pub_key || DH_set0_key(dh, pub_key, priv_key) != 1)
goto err;
pub_key = NULL;
priv_key = NULL;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index a9dbdef..a85ed32 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1135,6 +1135,7 @@
int ie_len;
struct hostapd_freq_params freq;
int beacon_int;
+ int dtim_period;
int max_peer_links;
struct wpa_driver_mesh_bss_params conf;
#define WPA_DRIVER_MESH_FLAG_USER_MPM 0x00000001
@@ -1278,6 +1279,8 @@
#define WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS 0x0000008000000000ULL
/** Driver supports full AP client state */
#define WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE 0x0000010000000000ULL
+/** Driver supports P2P Listen offload */
+#define WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD 0x0000020000000000ULL
u64 flags;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -1423,6 +1426,7 @@
u32 flags_mask; /* unset bits in flags */
#ifdef CONFIG_MESH
enum mesh_plink_state plink_state;
+ u16 peer_aid;
#endif /* CONFIG_MESH */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
@@ -3573,6 +3577,32 @@
int (*get_ext_capab)(void *priv, enum wpa_driver_if_type type,
const u8 **ext_capab, const u8 **ext_capab_mask,
unsigned int *ext_capab_len);
+
+ /**
+ * p2p_lo_start - Start offloading P2P listen to device
+ * @priv: Private driver interface data
+ * @freq: Listening frequency (MHz) for P2P listen
+ * @period: Length of the listen operation in milliseconds
+ * @interval: Interval for running the listen operation in milliseconds
+ * @count: Number of times to run the listen operation
+ * @device_types: Device primary and secondary types
+ * @dev_types_len: Number of bytes for device_types
+ * @ies: P2P IE and WSC IE for Probe Response frames
+ * @ies_len: Length of ies in bytes
+ * Returns: 0 on success or -1 on failure
+ */
+ int (*p2p_lo_start)(void *priv, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count,
+ const u8 *device_types, size_t dev_types_len,
+ const u8 *ies, size_t ies_len);
+
+ /**
+ * p2p_lo_stop - Stop P2P listen offload
+ * @priv: Private driver interface data
+ * Returns: 0 on success or -1 on failure
+ */
+ int (*p2p_lo_stop)(void *priv);
};
@@ -4057,6 +4087,11 @@
* on a DFS frequency by a driver that supports DFS Offload.
*/
EVENT_DFS_CAC_STARTED,
+
+ /**
+ * EVENT_P2P_LO_STOP - Notify that P2P listen offload is stopped
+ */
+ EVENT_P2P_LO_STOP,
};
@@ -4782,6 +4817,27 @@
u16 ch_width;
enum hostapd_hw_mode hw_mode;
} acs_selected_channels;
+
+ /**
+ * struct p2p_lo_stop - Reason code for P2P Listen offload stop event
+ * @reason_code: Reason for stopping offload
+ * P2P_LO_STOPPED_REASON_COMPLETE: Listen offload finished as
+ * scheduled.
+ * P2P_LO_STOPPED_REASON_RECV_STOP_CMD: Host requested offload to
+ * be stopped.
+ * P2P_LO_STOPPED_REASON_INVALID_PARAM: Invalid listen offload
+ * parameters.
+ * P2P_LO_STOPPED_REASON_NOT_SUPPORTED: Listen offload not
+ * supported by device.
+ */
+ struct p2p_lo_stop {
+ enum {
+ P2P_LO_STOPPED_REASON_COMPLETE = 0,
+ P2P_LO_STOPPED_REASON_RECV_STOP_CMD,
+ P2P_LO_STOPPED_REASON_INVALID_PARAM,
+ P2P_LO_STOPPED_REASON_NOT_SUPPORTED,
+ } reason_code;
+ } p2p_lo_stop;
};
/**
@@ -4861,6 +4917,8 @@
struct wowlan_triggers *
wpa_get_wowlan_triggers(const char *wowlan_triggers,
const struct wpa_driver_capa *capa);
+/* Convert driver flag to string */
+const char * driver_flag_to_string(u64 flag);
/* NULL terminated array of linked in driver wrappers */
extern const struct wpa_driver_ops *const wpa_drivers[];
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index b32d35f..c7107ba 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -80,6 +80,7 @@
E2S(NEW_PEER_CANDIDATE);
E2S(ACS_CHANNEL_SELECTED);
E2S(DFS_CAC_STARTED);
+ E2S(P2P_LO_STOP);
}
return "UNKNOWN";
@@ -218,3 +219,55 @@
os_free(buf);
return triggers;
}
+
+
+const char * driver_flag_to_string(u64 flag)
+{
+#define DF2S(x) case WPA_DRIVER_FLAGS_ ## x: return #x
+ switch (flag) {
+ DF2S(DRIVER_IE);
+ DF2S(SET_KEYS_AFTER_ASSOC);
+ DF2S(DFS_OFFLOAD);
+ DF2S(4WAY_HANDSHAKE);
+ DF2S(WIRED);
+ DF2S(SME);
+ DF2S(AP);
+ DF2S(SET_KEYS_AFTER_ASSOC_DONE);
+ DF2S(HT_2040_COEX);
+ DF2S(P2P_CONCURRENT);
+ DF2S(P2P_DEDICATED_INTERFACE);
+ DF2S(P2P_CAPABLE);
+ DF2S(AP_TEARDOWN_SUPPORT);
+ DF2S(P2P_MGMT_AND_NON_P2P);
+ DF2S(SANE_ERROR_CODES);
+ DF2S(OFFCHANNEL_TX);
+ DF2S(EAPOL_TX_STATUS);
+ DF2S(DEAUTH_TX_STATUS);
+ DF2S(BSS_SELECTION);
+ DF2S(TDLS_SUPPORT);
+ DF2S(TDLS_EXTERNAL_SETUP);
+ DF2S(PROBE_RESP_OFFLOAD);
+ DF2S(AP_UAPSD);
+ DF2S(INACTIVITY_TIMER);
+ DF2S(AP_MLME);
+ DF2S(SAE);
+ DF2S(OBSS_SCAN);
+ DF2S(IBSS);
+ DF2S(RADAR);
+ DF2S(DEDICATED_P2P_DEVICE);
+ DF2S(QOS_MAPPING);
+ DF2S(AP_CSA);
+ DF2S(MESH);
+ DF2S(ACS_OFFLOAD);
+ DF2S(KEY_MGMT_OFFLOAD);
+ DF2S(TDLS_CHANNEL_SWITCH);
+ DF2S(HT_IBSS);
+ DF2S(VHT_IBSS);
+ DF2S(SUPPORT_HW_MODE_ANY);
+ DF2S(OFFCHANNEL_SIMULTANEOUS);
+ DF2S(FULL_AP_CLIENT_STATE);
+ DF2S(P2P_LISTEN_OFFLOAD);
+ }
+ return "UNKNOWN";
+#undef DF2S
+}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c89665b..ae40f42 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -3468,6 +3468,17 @@
}
+static int nl80211_put_dtim_period(struct nl_msg *msg, int dtim_period)
+{
+ if (dtim_period > 0) {
+ wpa_printf(MSG_DEBUG, " * dtim_period=%d", dtim_period);
+ return nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
+ }
+
+ return 0;
+}
+
+
static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params)
{
@@ -3504,7 +3515,7 @@
nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
params->tail) ||
nl80211_put_beacon_int(msg, params->beacon_int) ||
- nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
+ nl80211_put_dtim_period(msg, params->dtim_period) ||
nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
goto fail;
if (params->proberesp && params->proberesp_len) {
@@ -3695,7 +3706,7 @@
"nl80211: Frequency set succeeded for ht2040 coex");
bss->bandwidth = params->freq->bandwidth;
}
- } else if (!beacon_set) {
+ } else if (!beacon_set && params->freq) {
/*
* cfg80211 updates the driver on frequence change in AP
* mode only at the point when beaconing is started, so
@@ -3777,6 +3788,12 @@
wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
return -ENOBUFS;
+ } else {
+ wpa_printf(MSG_DEBUG, " * channel_type=%d",
+ NL80211_CHAN_NO_HT);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_NO_HT))
+ return -ENOBUFS;
}
return 0;
}
@@ -3839,11 +3856,11 @@
static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
{
switch (state) {
- case PLINK_LISTEN:
+ case PLINK_IDLE:
return NL80211_PLINK_LISTEN;
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_SNT:
return NL80211_PLINK_OPN_SNT;
- case PLINK_OPEN_RCVD:
+ case PLINK_OPN_RCVD:
return NL80211_PLINK_OPN_RCVD;
case PLINK_CNF_RCVD:
return NL80211_PLINK_CNF_RCVD;
@@ -4032,6 +4049,15 @@
if (!(params->flags & WPA_STA_ASSOCIATED))
upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
}
+#ifdef CONFIG_MESH
+ } else {
+ if (params->plink_state == PLINK_ESTAB && params->peer_aid) {
+ ret = nla_put_u16(msg, NL80211_ATTR_MESH_PEER_AID,
+ params->peer_aid);
+ if (ret)
+ goto fail;
+ }
+#endif /* CONFIG_MESH */
}
wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
@@ -8391,7 +8417,8 @@
nl80211_put_freq_params(msg, ¶ms->freq) ||
nl80211_put_basic_rates(msg, params->basic_rates) ||
nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
- nl80211_put_beacon_int(msg, params->beacon_int))
+ nl80211_put_beacon_int(msg, params->beacon_int) ||
+ nl80211_put_dtim_period(msg, params->dtim_period))
goto fail;
wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
@@ -9117,6 +9144,89 @@
return 0;
}
+
+static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count, const u8 *device_types,
+ size_t dev_types_len,
+ const u8 *ies, size_t ies_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u",
+ freq, period, interval, count);
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!container)
+ goto fail;
+
+ if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
+ freq) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
+ period) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
+ interval) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
+ count) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
+ dev_types_len, device_types) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
+ ies_len, ies))
+ goto fail;
+
+ nla_nest_end(msg, container);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to send P2P Listen offload vendor command");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_p2p_lo_stop(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload");
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -9338,9 +9448,6 @@
.vendor_cmd = nl80211_vendor_cmd,
.set_qos_map = nl80211_set_qos_map,
.set_wowlan = nl80211_set_wowlan,
-#ifdef CONFIG_DRIVER_NL80211_QCA
- .roaming = nl80211_roaming,
-#endif /* CONFIG_DRIVER_NL80211_QCA */
.set_mac_addr = nl80211_set_mac_addr,
#ifdef CONFIG_MESH
.init_mesh = wpa_driver_nl80211_init_mesh,
@@ -9355,10 +9462,13 @@
.del_tx_ts = nl80211_del_ts,
.get_ifindex = nl80211_get_ifindex,
#ifdef CONFIG_DRIVER_NL80211_QCA
+ .roaming = nl80211_roaming,
.do_acs = wpa_driver_do_acs,
.set_band = nl80211_set_band,
.get_pref_freq_list = nl80211_get_pref_freq_list,
.set_prob_oper_freq = nl80211_set_prob_oper_freq,
+ .p2p_lo_start = nl80211_p2p_lo_start,
+ .p2p_lo_stop = nl80211_p2p_lo_stop,
#endif /* CONFIG_DRIVER_NL80211_QCA */
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
.get_ext_capab = nl80211_get_ext_capab,
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 1ebbdaa..1134886 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -972,6 +972,8 @@
if (check_feature(QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS,
&info))
drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD;
os_free(info.flags);
}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 961a2e4..762e3ac 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -916,6 +916,7 @@
struct nlattr *tb[])
{
unsigned int freq;
+ union wpa_event_data event;
if (tb[NL80211_ATTR_MAC] == NULL) {
wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
@@ -935,7 +936,10 @@
drv->first_bss->freq = freq;
}
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+ os_memset(&event, 0, sizeof(event));
+ event.assoc_info.freq = freq;
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
}
@@ -1872,6 +1876,31 @@
external_scan);
}
+
+static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv,
+ u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1];
+ union wpa_event_data event;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: P2P listen offload stop vendor event received");
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.p2p_lo_stop.reason_code =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON]);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: P2P Listen offload stop reason: %d",
+ event.p2p_lo_stop.reason_code);
+ wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event);
+}
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -1905,6 +1934,9 @@
case QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE:
qca_nl80211_scan_done_event(drv, data, len);
break;
+ case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP:
+ qca_nl80211_p2p_lo_stop_event(drv, data, len);
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
default:
wpa_printf(MSG_DEBUG,
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 53c8278..2206941 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -1829,6 +1829,44 @@
* %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per
* interface type.
*
+ * @NL80211_ATTR_MU_MIMO_GROUP_DATA: array of 24 bytes that defines a MU-MIMO
+ * groupID for monitor mode.
+ * The first 8 bytes are a mask that defines the membership in each
+ * group (there are 64 groups, group 0 and 63 are reserved),
+ * each bit represents a group and set to 1 for being a member in
+ * that group and 0 for not being a member.
+ * The remaining 16 bytes define the position in each group: 2 bits for
+ * each group.
+ * (smaller group numbers represented on most significant bits and bigger
+ * group numbers on least significant bits.)
+ * This attribute is used only if all interfaces are in monitor mode.
+ * Set this attribute in order to monitor packets using the given MU-MIMO
+ * groupID data.
+ * to turn off that feature set all the bits of the groupID to zero.
+ * @NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR: mac address for the sniffer to follow
+ * when using MU-MIMO air sniffer.
+ * to turn that feature off set an invalid mac address
+ * (e.g. FF:FF:FF:FF:FF:FF)
+ *
+ * @NL80211_ATTR_SCAN_START_TIME_TSF: The time at which the scan was actually
+ * started (u64). The time is the TSF of the BSS the interface that
+ * requested the scan is connected to (if available, otherwise this
+ * attribute must not be included).
+ * @NL80211_ATTR_SCAN_START_TIME_TSF_BSSID: The BSS according to which
+ * %NL80211_ATTR_SCAN_START_TIME_TSF is set.
+ * @NL80211_ATTR_MEASUREMENT_DURATION: measurement duration in TUs (u16). If
+ * %NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY is not set, this is the
+ * maximum measurement duration allowed. This attribute is used with
+ * measurement requests. It can also be used with %NL80211_CMD_TRIGGER_SCAN
+ * if the scan is used for beacon report radio measurement.
+ * @NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY: flag attribute that indicates
+ * that the duration specified with %NL80211_ATTR_MEASUREMENT_DURATION is
+ * mandatory. If this flag is not set, the duration is the maximum duration
+ * and the actual measurement duration may be shorter.
+ *
+ * @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is
+ * used to pull the stored data for mesh peer in power save state.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2213,6 +2251,16 @@
NL80211_ATTR_IFTYPE_EXT_CAPA,
+ NL80211_ATTR_MU_MIMO_GROUP_DATA,
+ NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR,
+
+ NL80211_ATTR_SCAN_START_TIME_TSF,
+ NL80211_ATTR_SCAN_START_TIME_TSF_BSSID,
+ NL80211_ATTR_MEASUREMENT_DURATION,
+ NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY,
+
+ NL80211_ATTR_MESH_PEER_AID,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3474,6 +3522,12 @@
* was last updated by a received frame. The value is expected to be
* accurate to about 10ms. (u64, nanoseconds)
* @NL80211_BSS_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_BSS_PARENT_TSF: the time at the start of reception of the first
+ * octet of the timestamp field of the last beacon/probe received for
+ * this BSS. The time is the TSF of the BSS specified by
+ * @NL80211_BSS_PARENT_BSSID. (u64).
+ * @NL80211_BSS_PARENT_BSSID: the BSS according to which @NL80211_BSS_PARENT_TSF
+ * is set.
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -3495,6 +3549,8 @@
NL80211_BSS_PRESP_DATA,
NL80211_BSS_LAST_SEEN_BOOTTIME,
NL80211_BSS_PAD,
+ NL80211_BSS_PARENT_TSF,
+ NL80211_BSS_PARENT_BSSID,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@@ -4479,6 +4535,22 @@
* %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set
* the ASSOC_REQ_USE_RRM flag in the association request even if
* NL80211_FEATURE_QUIET is not advertized.
+ * @NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER: This device supports MU-MIMO air
+ * sniffer which means that it can be configured to hear packets from
+ * certain groups which can be configured by the
+ * %NL80211_ATTR_MU_MIMO_GROUP_DATA attribute,
+ * or can be configured to follow a station by configuring the
+ * %NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR attribute.
+ * @NL80211_EXT_FEATURE_SCAN_START_TIME: This driver includes the actual
+ * time the scan started in scan results event. The time is the TSF of
+ * the BSS that the interface that requested the scan is connected to
+ * (if available).
+ * @NL80211_EXT_FEATURE_BSS_PARENT_TSF: Per BSS, this driver reports the
+ * time the last beacon/probe was received. The time is the TSF of the
+ * BSS that the interface that requested the scan is connected to
+ * (if available).
+ * @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of
+ * channel dwell time.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4486,6 +4558,10 @@
enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_VHT_IBSS,
NL80211_EXT_FEATURE_RRM,
+ NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER,
+ NL80211_EXT_FEATURE_SCAN_START_TIME,
+ NL80211_EXT_FEATURE_BSS_PARENT_TSF,
+ NL80211_EXT_FEATURE_SET_SCAN_DWELL,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index a209a56..996b4e8 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -788,11 +788,11 @@
dev->oper_ssid_len = msg.ssid[1];
}
- if (msg.adv_service_instance && msg.adv_service_instance_len) {
- wpabuf_free(dev->info.p2ps_instance);
+ wpabuf_free(dev->info.p2ps_instance);
+ dev->info.p2ps_instance = NULL;
+ if (msg.adv_service_instance && msg.adv_service_instance_len)
dev->info.p2ps_instance = wpabuf_alloc_copy(
msg.adv_service_instance, msg.adv_service_instance_len);
- }
if (freq >= 2412 && freq <= 2484 && msg.ds_params &&
*msg.ds_params >= 1 && *msg.ds_params <= 14) {
@@ -2234,6 +2234,58 @@
return buf;
}
+static int p2p_build_probe_resp_buf(struct p2p_data *p2p, struct wpabuf *buf,
+ struct wpabuf *ies,
+ const u8 *addr, int rx_freq)
+{
+ struct ieee80211_mgmt *resp;
+ u8 channel, op_class;
+
+ resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+ u.probe_resp.variable));
+
+ resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_PROBE_RESP << 4));
+ os_memcpy(resp->da, addr, ETH_ALEN);
+ os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
+ os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
+ resp->u.probe_resp.beacon_int = host_to_le16(100);
+ /* hardware or low-level driver will setup seq_ctrl and timestamp */
+ resp->u.probe_resp.capab_info =
+ host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
+ WLAN_CAPABILITY_PRIVACY |
+ WLAN_CAPABILITY_SHORT_SLOT_TIME);
+
+ wpabuf_put_u8(buf, WLAN_EID_SSID);
+ wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
+ wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+
+ wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
+ wpabuf_put_u8(buf, 8);
+ wpabuf_put_u8(buf, (60 / 5) | 0x80);
+ wpabuf_put_u8(buf, 90 / 5);
+ wpabuf_put_u8(buf, (120 / 5) | 0x80);
+ wpabuf_put_u8(buf, 180 / 5);
+ wpabuf_put_u8(buf, (240 / 5) | 0x80);
+ wpabuf_put_u8(buf, 360 / 5);
+ wpabuf_put_u8(buf, 480 / 5);
+ wpabuf_put_u8(buf, 540 / 5);
+
+ if (!rx_freq) {
+ channel = p2p->cfg->channel;
+ } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+ p2p_err(p2p, "Failed to convert freq to channel");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
+ wpabuf_put_u8(buf, 1);
+ wpabuf_put_u8(buf, channel);
+
+ wpabuf_put_buf(buf, ies);
+
+ return 0;
+}
static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
{
@@ -2267,10 +2319,8 @@
{
struct ieee802_11_elems elems;
struct wpabuf *buf;
- struct ieee80211_mgmt *resp;
struct p2p_message msg;
struct wpabuf *ies;
- u8 channel, op_class;
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
ParseFailed) {
@@ -2414,49 +2464,12 @@
return P2P_PREQ_NOT_PROCESSED;
}
- resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
- u.probe_resp.variable));
-
- resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
- (WLAN_FC_STYPE_PROBE_RESP << 4));
- os_memcpy(resp->da, addr, ETH_ALEN);
- os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
- os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
- resp->u.probe_resp.beacon_int = host_to_le16(100);
- /* hardware or low-level driver will setup seq_ctrl and timestamp */
- resp->u.probe_resp.capab_info =
- host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
- WLAN_CAPABILITY_PRIVACY |
- WLAN_CAPABILITY_SHORT_SLOT_TIME);
-
- wpabuf_put_u8(buf, WLAN_EID_SSID);
- wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
- wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
-
- wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
- wpabuf_put_u8(buf, 8);
- wpabuf_put_u8(buf, (60 / 5) | 0x80);
- wpabuf_put_u8(buf, 90 / 5);
- wpabuf_put_u8(buf, (120 / 5) | 0x80);
- wpabuf_put_u8(buf, 180 / 5);
- wpabuf_put_u8(buf, (240 / 5) | 0x80);
- wpabuf_put_u8(buf, 360 / 5);
- wpabuf_put_u8(buf, 480 / 5);
- wpabuf_put_u8(buf, 540 / 5);
-
- if (!rx_freq) {
- channel = p2p->cfg->channel;
- } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+ if (p2p_build_probe_resp_buf(p2p, buf, ies, addr, rx_freq)) {
wpabuf_free(ies);
wpabuf_free(buf);
return P2P_PREQ_NOT_PROCESSED;
}
- wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
- wpabuf_put_u8(buf, 1);
- wpabuf_put_u8(buf, channel);
-
- wpabuf_put_buf(buf, ies);
wpabuf_free(ies);
p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf, rx_freq);
@@ -2470,12 +2483,18 @@
enum p2p_probe_req_status
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
const u8 *bssid, const u8 *ie, size_t ie_len,
- unsigned int rx_freq)
+ unsigned int rx_freq, int p2p_lo_started)
{
enum p2p_probe_req_status res;
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
+ if (p2p_lo_started) {
+ p2p_dbg(p2p,
+ "Probe Response is offloaded, do not reply Probe Request");
+ return P2P_PREQ_PROCESSED;
+ }
+
res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len, rx_freq);
if (res != P2P_PREQ_PROCESSED && res != P2P_PREQ_NOT_PROCESSED)
return res;
@@ -2980,7 +2999,6 @@
os_free(p2p->groups);
p2ps_prov_free(p2p);
wpabuf_free(p2p->sd_resp);
- os_free(p2p->after_scan_tx);
p2p_remove_wps_vendor_extensions(p2p);
os_free(p2p->no_go_freq.range);
p2p_service_flush_asp(p2p);
@@ -5490,3 +5508,34 @@
i, p2p->pref_freq_list[i]);
}
}
+
+
+struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
+ unsigned int freq)
+{
+ struct wpabuf *ies, *buf;
+ u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ int ret;
+
+ ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
+ if (!ies) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: Failed to build Probe Response IEs");
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(200 + wpabuf_len(ies));
+ if (!buf) {
+ wpabuf_free(ies);
+ return NULL;
+ }
+
+ ret = p2p_build_probe_resp_buf(p2p, buf, ies, addr, freq);
+ wpabuf_free(ies);
+ if (ret) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ return buf;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 186af36..5b5a0bf 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1555,12 +1555,13 @@
* @ie: Information elements from the Probe Request frame body
* @ie_len: Length of ie buffer in octets
* @rx_freq: Probe Request frame RX frequency
+ * @p2p_lo_started: Whether P2P Listen Offload is started
* Returns: value indicating the type and status of the probe request
*/
enum p2p_probe_req_status
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
const u8 *bssid, const u8 *ie, size_t ie_len,
- unsigned int rx_freq);
+ unsigned int rx_freq, int p2p_lo_started);
/**
* p2p_rx_action - Report received Action frame
@@ -2383,4 +2384,7 @@
int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
unsigned int *num);
+struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
+ unsigned int freq);
+
#endif /* P2P_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 0571c23..ce631dd 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2669,9 +2669,8 @@
return props;
err:
- value = *props;
- while (value)
- os_free(value++);
+ for (i = 0; props[i]; i++)
+ os_free(props[i]);
os_free(props);
return NULL;
#endif /* NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index e75323d..4aa0f24 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -6283,6 +6283,21 @@
return 0;
}
+
+static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int freq = 0, period = 0, interval = 0, count = 0;
+
+ if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
+ {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
+ return -1;
+ }
+
+ return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
+}
+
#endif /* CONFIG_P2P */
@@ -6983,6 +6998,34 @@
}
+static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) wpa_s->drv_flags);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (wpa_s->drv_flags & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -7213,6 +7256,10 @@
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
wpa_s->wnmsleep_used = 0;
+
+#ifdef CONFIG_SME
+ wpa_s->sme.last_unprot_disconnect.sec = 0;
+#endif /* CONFIG_SME */
}
@@ -8968,6 +9015,12 @@
} else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
+ if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
+ if (wpas_p2p_lo_stop(wpa_s))
+ reply_len = -1;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
@@ -9032,7 +9085,10 @@
if (del_hs20_icon(wpa_s, buf + 14) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "FETCH_OSU") == 0) {
- if (hs20_fetch_osu(wpa_s) < 0)
+ if (hs20_fetch_osu(wpa_s, 0) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
+ if (hs20_fetch_osu(wpa_s, 1) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
hs20_cancel_fetch_osu(wpa_s);
@@ -9243,6 +9299,9 @@
if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
reply_len = -1;
#endif /* CONFIG_AUTOSCAN */
+ } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+ reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
+ reply_size);
#ifdef ANDROID
} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 9f104f5..396a0dc 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -946,4 +946,27 @@
&wpa_s->extended_capa_len);
}
+static inline int wpa_drv_p2p_lo_start(struct wpa_supplicant *wpa_s,
+ unsigned int channel,
+ unsigned int period,
+ unsigned int interval,
+ unsigned int count,
+ const u8 *device_types,
+ size_t dev_types_len,
+ const u8 *ies, size_t ies_len)
+{
+ if (!wpa_s->driver->p2p_lo_start)
+ return -1;
+ return wpa_s->driver->p2p_lo_start(wpa_s->drv_priv, channel, period,
+ interval, count, device_types,
+ dev_types_len, ies, ies_len);
+}
+
+static inline int wpa_drv_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->driver->p2p_lo_stop)
+ return -1;
+ return wpa_s->driver->p2p_lo_stop(wpa_s->drv_priv);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index b7a3bc0..50461b6 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1014,8 +1014,10 @@
continue;
}
- if (!bss_is_ess(bss) && !bss_is_pbss(bss)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - neither ESS nor PBSS network");
+ if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) &&
+ !bss_is_pbss(bss)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - not ESS, PBSS, or MBSS");
continue;
}
@@ -1031,6 +1033,14 @@
continue;
}
+#ifdef CONFIG_MESH
+ if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 &&
+ ssid->frequency != bss->freq) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not allowed (mesh)");
+ continue;
+ }
+#endif /* CONFIG_MESH */
+
if (!rate_match(wpa_s, bss)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do "
"not match");
@@ -1624,6 +1634,14 @@
selected = wpa_supplicant_pick_network(wpa_s, &ssid);
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Avoiding join because we already joined a mesh group");
+ return 0;
+ }
+#endif /* CONFIG_MESH */
+
if (selected) {
int skip;
skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
@@ -1652,13 +1670,6 @@
*/
return 1;
} else {
-#ifdef CONFIG_MESH
- if (wpa_s->ifmsh) {
- wpa_msg(wpa_s, MSG_INFO,
- "Avoiding join because we already joined a mesh group");
- return 0;
- }
-#endif /* CONFIG_MESH */
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -4067,6 +4078,14 @@
&data->acs_selected_channels);
#endif /* CONFIG_ACS */
break;
+ case EVENT_P2P_LO_STOP:
+#ifdef CONFIG_P2P
+ wpa_s->p2p_lo_started = 0;
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_LISTEN_OFFLOAD_STOP
+ P2P_LISTEN_OFFLOAD_STOP_REASON "reason=%d",
+ data->p2p_lo_stop.reason_code);
+#endif /* CONFIG_P2P */
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index a62c1c3..e88f147 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -205,8 +205,8 @@
}
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
- size_t payload_len)
+static struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+ size_t payload_len)
{
struct wpabuf *buf;
@@ -320,7 +320,7 @@
return -1;
b64 = base64_encode(&icon->image[offset], size, &b64_size);
- if (buf_len >= b64_size) {
+ if (b64 && buf_len >= b64_size) {
os_memcpy(reply, b64, b64_size);
reply_size = b64_size;
} else {
@@ -436,14 +436,14 @@
icon->image_len = slen;
hs20_remove_duplicate_icons(wpa_s, icon);
wpa_msg(wpa_s, MSG_INFO,
- "RX-HS20-ICON " MACSTR " %s %u",
+ RX_HS20_ICON MACSTR " %s %u",
MAC2STR(sa), icon->file_name,
(unsigned int) icon->image_len);
return 0;
}
}
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File",
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File",
MAC2STR(sa));
if (slen < 4) {
@@ -506,7 +506,7 @@
}
fclose(f);
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname);
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname);
return 0;
}
@@ -570,7 +570,7 @@
switch (subtype) {
case HS20_STYPE_CAPABILITY_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" HS Capability List", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
if (anqp) {
@@ -580,7 +580,7 @@
}
break;
case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Operator Friendly Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
if (anqp) {
@@ -596,7 +596,7 @@
"Metrics value from " MACSTR, MAC2STR(sa));
break;
}
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
pos[9], pos[10], WPA_GET_LE16(pos + 11));
@@ -606,7 +606,7 @@
}
break;
case HS20_STYPE_CONNECTION_CAPABILITY:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Connection Capability", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
if (anqp) {
@@ -616,7 +616,7 @@
}
break;
case HS20_STYPE_OPERATING_CLASS:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Operating Class", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
if (anqp) {
@@ -626,7 +626,7 @@
}
break;
case HS20_STYPE_OSU_PROVIDERS_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" OSU Providers list", MAC2STR(sa));
wpa_s->num_prov_found++;
if (anqp) {
@@ -703,6 +703,8 @@
wpa_s->conf->osu_dir);
f = fopen(fname, "w");
if (f == NULL) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not write OSU provider information");
hs20_free_osu_prov(wpa_s);
wpa_s->fetch_anqp_in_progress = 0;
return;
@@ -1076,7 +1078,7 @@
}
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan)
{
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
@@ -1107,7 +1109,16 @@
wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch");
wpa_s->num_osu_scans = 0;
wpa_s->num_prov_found = 0;
- hs20_start_osu_scan(wpa_s);
+ if (skip_scan) {
+ wpa_s->network_select = 0;
+ wpa_s->fetch_all_anqp = 1;
+ wpa_s->fetch_osu_info = 1;
+ wpa_s->fetch_osu_icon_in_progress = 0;
+
+ interworking_start_fetch_anqp(wpa_s);
+ } else {
+ hs20_start_osu_scan(wpa_s);
+ }
return 0;
}
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 89c47a5..0dd559f 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -13,8 +13,6 @@
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
const u8 *payload, size_t payload_len, int inmem);
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
- size_t payload_len);
void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
struct wpabuf *buf);
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
@@ -33,7 +31,7 @@
void hs20_free_osu_prov(struct wpa_supplicant *wpa_s);
void hs20_next_osu_icon(struct wpa_supplicant *wpa_s);
void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s);
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s);
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan);
void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s);
void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s);
void hs20_start_osu_scan(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 589ee57..697810e 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -950,11 +950,9 @@
if (!key_mgmt)
key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
- if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0)
- return -1;
- if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
- return -1;
- if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
+ if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
+ wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
+ wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
return -1;
return 0;
}
@@ -1590,9 +1588,8 @@
}
-static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss, int allow_excluded,
- int only_add)
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ int only_add)
{
struct wpa_cred *cred, *cred_rc, *cred_3gpp;
struct wpa_ssid *ssid;
@@ -1600,7 +1597,7 @@
struct nai_realm_eap *eap = NULL;
u16 count, i;
char buf[100];
- int excluded = 0, *excl = allow_excluded ? &excluded : NULL;
+ int excluded = 0, *excl = &excluded;
const char *name;
if (wpa_s->conf->cred == NULL || bss == NULL)
@@ -1614,8 +1611,8 @@
}
wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR
- " for connection (allow_excluded=%d)",
- MAC2STR(bss->bssid), allow_excluded);
+ " for connection",
+ MAC2STR(bss->bssid));
if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
/*
@@ -1633,7 +1630,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest roaming consortium matching credential priority %d sp_priority %d",
cred_rc->priority, cred_rc->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1642,7 +1639,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d",
cred->priority, cred->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1652,7 +1649,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest 3GPP matching credential priority %d sp_priority %d",
cred_3gpp->priority, cred_3gpp->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1665,7 +1662,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest roaming consortium matching credential priority %d sp_priority %d (ignore BW)",
cred_rc->priority, cred_rc->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1675,7 +1672,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d (ignore BW)",
cred->priority, cred->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1685,7 +1682,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest 3GPP matching credential priority %d sp_priority %d (ignore BW)",
cred_3gpp->priority, cred_3gpp->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
}
@@ -1850,13 +1847,6 @@
}
-int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- int only_add)
-{
- return interworking_connect_helper(wpa_s, bss, 1, only_add);
-}
-
-
#ifdef PCSC_FUNCS
static int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s)
{
@@ -2806,7 +2796,7 @@
switch (info_id) {
case ANQP_CAPABILITY_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" ANQP Capability list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list",
pos, slen);
@@ -2816,7 +2806,7 @@
}
break;
case ANQP_VENUE_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Venue Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
if (anqp) {
@@ -2825,7 +2815,7 @@
}
break;
case ANQP_NETWORK_AUTH_TYPE:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Network Authentication Type information",
MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
@@ -2836,7 +2826,7 @@
}
break;
case ANQP_ROAMING_CONSORTIUM:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Roaming Consortium list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
pos, slen);
@@ -2846,7 +2836,7 @@
}
break;
case ANQP_IP_ADDR_TYPE_AVAILABILITY:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" IP Address Type Availability information",
MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
@@ -2858,7 +2848,7 @@
}
break;
case ANQP_NAI_REALM:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" NAI Realm list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
if (anqp) {
@@ -2867,7 +2857,7 @@
}
break;
case ANQP_3GPP_CELLULAR_NETWORK:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" 3GPP Cellular Network information", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
pos, slen);
@@ -2877,7 +2867,7 @@
}
break;
case ANQP_DOMAIN_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Domain Name list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
if (anqp) {
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index c37d547..5b5c3e6 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -532,9 +532,26 @@
return NOT_ALLOWED;
res2 = allow_channel(mode, channel + 4, NULL);
} else if (bw == BW80) {
- res2 = verify_80mhz(mode, channel);
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 80 MHz specific version.
+ */
+ res2 = res = verify_80mhz(mode, channel);
} else if (bw == BW160) {
- res2 = verify_160mhz(mode, channel);
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 160 MHz specific version.
+ */
+ res2 = res = verify_160mhz(mode, channel);
+ } else if (bw == BW80P80) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 80 MHz specific version.
+ */
+ res2 = res = verify_80mhz(mode, channel);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -550,38 +567,63 @@
int chan;
size_t i;
struct hostapd_hw_modes *mode;
+ int found;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
if (!mode)
return 0;
- if (op_class->op_class == 128 || op_class->op_class == 130) {
+ if (op_class->op_class == 128) {
u8 channels[] = { 42, 58, 106, 122, 138, 155 };
for (i = 0; i < ARRAY_SIZE(channels); i++) {
if (verify_channel(mode, channels[i], op_class->bw) ==
- NOT_ALLOWED)
- return 0;
+ ALLOWED)
+ return 1;
}
- return 1;
+ return 0;
}
if (op_class->op_class == 129) {
- if (verify_channel(mode, 50, op_class->bw) == NOT_ALLOWED ||
- verify_channel(mode, 114, op_class->bw) == NOT_ALLOWED)
- return 0;
-
- return 1;
+ /* Check if either 160 MHz channels is allowed */
+ return verify_channel(mode, 50, op_class->bw) == ALLOWED ||
+ verify_channel(mode, 114, op_class->bw) == ALLOWED;
}
+ if (op_class->op_class == 130) {
+ /* Need at least two non-contiguous 80 MHz segments */
+ found = 0;
+
+ if (verify_channel(mode, 42, op_class->bw) == ALLOWED ||
+ verify_channel(mode, 58, op_class->bw) == ALLOWED)
+ found++;
+ if (verify_channel(mode, 106, op_class->bw) == ALLOWED ||
+ verify_channel(mode, 122, op_class->bw) == ALLOWED ||
+ verify_channel(mode, 138, op_class->bw) == ALLOWED)
+ found++;
+ if (verify_channel(mode, 106, op_class->bw) == ALLOWED &&
+ verify_channel(mode, 138, op_class->bw) == ALLOWED)
+ found++;
+ if (verify_channel(mode, 155, op_class->bw) == ALLOWED)
+ found++;
+
+ if (found >= 2)
+ return 1;
+
+ return 0;
+ }
+
+ found = 0;
for (chan = op_class->min_chan; chan <= op_class->max_chan;
chan += op_class->inc) {
- if (verify_channel(mode, chan, op_class->bw) == NOT_ALLOWED)
- return 0;
+ if (verify_channel(mode, chan, op_class->bw) == ALLOWED) {
+ found = 1;
+ break;
+ }
}
- return 1;
+ return found;
}
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index dd534d4..cdfe51c 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -400,6 +400,10 @@
params.beacon_int = ssid->beacon_int;
else if (wpa_s->conf->beacon_int > 0)
params.beacon_int = wpa_s->conf->beacon_int;
+ if (ssid->dtim_period > 0)
+ params.dtim_period = ssid->dtim_period;
+ else if (wpa_s->conf->dtim_period > 0)
+ params.dtim_period = wpa_s->conf->dtim_period;
params.max_peer_links = wpa_s->conf->max_peer_links;
if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 8f327d8..7ffdefe 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -35,19 +35,17 @@
PLINK_UNDEFINED,
OPN_ACPT,
OPN_RJCT,
- OPN_IGNR,
CNF_ACPT,
CNF_RJCT,
- CNF_IGNR,
CLS_ACPT,
- CLS_IGNR
+ REQ_RJCT
};
static const char * const mplstate[] = {
[0] = "UNINITIALIZED",
- [PLINK_LISTEN] = "LISTEN",
- [PLINK_OPEN_SENT] = "OPEN_SENT",
- [PLINK_OPEN_RCVD] = "OPEN_RCVD",
+ [PLINK_IDLE] = "IDLE",
+ [PLINK_OPN_SNT] = "OPN_SNT",
+ [PLINK_OPN_RCVD] = "OPN_RCVD",
[PLINK_CNF_RCVD] = "CNF_RCVD",
[PLINK_ESTAB] = "ESTAB",
[PLINK_HOLDING] = "HOLDING",
@@ -58,12 +56,10 @@
[PLINK_UNDEFINED] = "UNDEFINED",
[OPN_ACPT] = "OPN_ACPT",
[OPN_RJCT] = "OPN_RJCT",
- [OPN_IGNR] = "OPN_IGNR",
[CNF_ACPT] = "CNF_ACPT",
[CNF_RJCT] = "CNF_RJCT",
- [CNF_IGNR] = "CNF_IGNR",
[CLS_ACPT] = "CLS_ACPT",
- [CLS_IGNR] = "CLS_IGNR"
+ [REQ_RJCT] = "REQ_RJCT",
};
@@ -195,12 +191,13 @@
sta->my_lid = llid;
sta->peer_lid = 0;
+ sta->peer_aid = 0;
/*
* We do not use wpa_mesh_set_plink_state() here because there is no
* entry in kernel yet.
*/
- sta->plink_state = PLINK_LISTEN;
+ sta->plink_state = PLINK_IDLE;
}
@@ -394,6 +391,7 @@
os_memset(¶ms, 0, sizeof(params));
params.addr = sta->addr;
params.plink_state = state;
+ params.peer_aid = sta->peer_aid;
params.set = 1;
ret = wpa_drv_sta_add(wpa_s, ¶ms);
@@ -424,8 +422,8 @@
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
switch (sta->plink_state) {
- case PLINK_OPEN_RCVD:
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_RCVD:
+ case PLINK_OPN_SNT:
/* retry timer */
if (sta->mpm_retries < conf->dot11MeshMaxRetries) {
eloop_register_timeout(
@@ -559,7 +557,7 @@
return -1;
}
- if ((PLINK_OPEN_SENT <= sta->plink_state &&
+ if ((PLINK_OPN_SNT <= sta->plink_state &&
sta->plink_state <= PLINK_ESTAB) ||
(sta->sae && sta->sae->state > SAE_NOTHING)) {
wpa_msg(wpa_s, MSG_INFO,
@@ -568,7 +566,7 @@
}
if (conf->security == MESH_CONF_SEC_NONE) {
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
} else {
mesh_rsn_auth_sae_sta(wpa_s, sta);
os_memcpy(hapd->mesh_required_peer, addr, ETH_ALEN);
@@ -631,7 +629,7 @@
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
}
/*
@@ -700,6 +698,7 @@
params.addr = addr;
params.plink_state = sta->plink_state;
params.aid = sta->aid;
+ params.peer_aid = sta->peer_aid;
params.listen_interval = 100;
params.ht_capabilities = sta->ht_capabilities;
params.vht_capabilities = sta->vht_capabilities;
@@ -770,9 +769,9 @@
}
if (conf->security == MESH_CONF_SEC_NONE) {
- if (sta->plink_state < PLINK_OPEN_SENT ||
+ if (sta->plink_state < PLINK_OPN_SNT ||
sta->plink_state > PLINK_ESTAB)
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
} else {
mesh_rsn_auth_sae_sta(wpa_s, sta);
}
@@ -847,36 +846,40 @@
static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
- enum plink_event event)
+ enum plink_event event, u16 reason)
{
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
- u16 reason = 0;
wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
MAC2STR(sta->addr), mplstate[sta->plink_state],
mplevent[event]);
switch (sta->plink_state) {
- case PLINK_LISTEN:
+ case PLINK_IDLE:
switch (event) {
case CLS_ACPT:
mesh_mpm_fsm_restart(wpa_s, sta);
break;
case OPN_ACPT:
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_RCVD);
mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
0);
break;
+ case REQ_RJCT:
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
default:
break;
}
break;
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_SNT:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -891,7 +894,7 @@
break;
case OPN_ACPT:
/* retry timer is left untouched */
- wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPN_RCVD);
mesh_mpm_send_plink_action(wpa_s, sta,
PLINK_CONFIRM, 0);
break;
@@ -907,11 +910,12 @@
break;
}
break;
- case PLINK_OPEN_RCVD:
+ case PLINK_OPN_RCVD:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -942,7 +946,8 @@
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -969,9 +974,12 @@
break;
case PLINK_ESTAB:
switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
- reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
eloop_register_timeout(
conf->dot11MeshHoldingTimeout / 1000,
@@ -1032,13 +1040,14 @@
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
struct sta_info *sta;
- u16 plid = 0, llid = 0;
+ u16 plid = 0, llid = 0, aid = 0;
enum plink_event event;
struct ieee802_11_elems elems;
struct mesh_peer_mgmt_ie peer_mgmt_ie;
const u8 *ies;
size_t ie_len;
int ret;
+ u16 reason = 0;
if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
return;
@@ -1069,7 +1078,8 @@
ie_len -= 2;
}
if (action_field == PLINK_CONFIRM) {
- wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies));
+ aid = WPA_GET_LE16(ies);
+ wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", aid);
ies += 2; /* aid */
ie_len -= 2;
}
@@ -1113,6 +1123,10 @@
llid = WPA_GET_LE16(peer_mgmt_ie.plid);
wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
+ if (action_field == PLINK_CLOSE)
+ wpa_printf(MSG_DEBUG, "MPM: close reason=%u",
+ WPA_GET_LE16(peer_mgmt_ie.reason));
+
sta = ap_get_sta(hapd, mgmt->sa);
/*
@@ -1140,13 +1154,24 @@
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
- if ((mconf->security & MESH_CONF_SEC_AMPE) &&
- mesh_rsn_process_ampe(wpa_s, sta, &elems,
- &mgmt->u.action.category,
- peer_mgmt_ie.chosen_pmk,
- ies, ie_len)) {
- wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame");
- return;
+ if (mconf->security & MESH_CONF_SEC_AMPE) {
+ int res;
+
+ res = mesh_rsn_process_ampe(wpa_s, sta, &elems,
+ &mgmt->u.action.category,
+ peer_mgmt_ie.chosen_pmk,
+ ies, ie_len);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: RSN process rejected frame (res=%d)",
+ res);
+ if (action_field == PLINK_OPEN && res == -2) {
+ /* AES-SIV decryption failed */
+ mesh_mpm_fsm(wpa_s, sta, OPN_RJCT,
+ WLAN_REASON_MESH_INVALID_GTK);
+ }
+ return;
+ }
}
if (sta->plink_state == PLINK_BLOCKED) {
@@ -1158,12 +1183,16 @@
switch (action_field) {
case PLINK_OPEN:
if (plink_free_count(hapd) == 0) {
- event = OPN_IGNR;
+ event = REQ_RJCT;
+ reason = WLAN_REASON_MESH_MAX_PEERS;
wpa_printf(MSG_INFO,
"MPM: Peer link num over quota(%d)",
hapd->max_plinks);
} else if (sta->peer_lid && sta->peer_lid != plid) {
- event = OPN_IGNR;
+ wpa_printf(MSG_DEBUG,
+ "MPM: peer_lid mismatch: 0x%x != 0x%x",
+ sta->peer_lid, plid);
+ return; /* no FSM event */
} else {
sta->peer_lid = plid;
event = OPN_ACPT;
@@ -1171,16 +1200,21 @@
break;
case PLINK_CONFIRM:
if (plink_free_count(hapd) == 0) {
- event = CNF_IGNR;
+ event = REQ_RJCT;
+ reason = WLAN_REASON_MESH_MAX_PEERS;
wpa_printf(MSG_INFO,
"MPM: Peer link num over quota(%d)",
hapd->max_plinks);
} else if (sta->my_lid != llid ||
(sta->peer_lid && sta->peer_lid != plid)) {
- event = CNF_IGNR;
+ wpa_printf(MSG_DEBUG,
+ "MPM: lid mismatch: my_lid: 0x%x != 0x%x or peer_lid: 0x%x != 0x%x",
+ sta->my_lid, llid, sta->peer_lid, plid);
+ return; /* no FSM event */
} else {
if (!sta->peer_lid)
sta->peer_lid = plid;
+ sta->peer_aid = aid;
event = CNF_ACPT;
}
break;
@@ -1196,12 +1230,19 @@
* restarted.
*/
event = CLS_ACPT;
- else if (sta->peer_lid != plid)
- event = CLS_IGNR;
- else if (peer_mgmt_ie.plid && sta->my_lid != llid)
- event = CLS_IGNR;
- else
+ else if (sta->peer_lid != plid) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: peer_lid mismatch: 0x%x != 0x%x",
+ sta->peer_lid, plid);
+ return; /* no FSM event */
+ } else if (peer_mgmt_ie.plid && sta->my_lid != llid) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: my_lid mismatch: 0x%x != 0x%x",
+ sta->my_lid, llid);
+ return; /* no FSM event */
+ } else {
event = CLS_ACPT;
+ }
break;
default:
/*
@@ -1211,7 +1252,7 @@
*/
return;
}
- mesh_mpm_fsm(wpa_s, sta, event);
+ mesh_mpm_fsm(wpa_s, sta, event, reason);
}
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 2eec227..27ab8cb 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -504,9 +504,11 @@
int ret = 0;
size_t len;
- len = sizeof(*ampe) + rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
+ len = sizeof(*ampe);
+ if (cat[1] == PLINK_OPEN)
+ len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
#ifdef CONFIG_IEEE80211W
- if (rsn->igtk_len)
+ if (cat[1] == PLINK_OPEN && rsn->igtk_len)
len += 2 + 6 + rsn->igtk_len;
#endif /* CONFIG_IEEE80211W */
@@ -532,6 +534,8 @@
os_memcpy(ampe->peer_nonce, sta->peer_nonce, WPA_NONCE_LEN);
pos = (u8 *) (ampe + 1);
+ if (cat[1] != PLINK_OPEN)
+ goto skip_keys;
/* TODO: Key Replay Counter[8] optionally for
* Mesh Group Key Inform/Acknowledge frames */
@@ -563,6 +567,7 @@
}
#endif /* CONFIG_IEEE80211W */
+skip_keys:
wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
ampe_ie, 2 + len);
@@ -648,7 +653,7 @@
if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3,
aad, aad_len, ampe_buf)) {
wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!");
- ret = -1;
+ ret = -2;
goto free;
}
@@ -683,6 +688,28 @@
* frames */
/*
+ * GTKdata shall not be included in Mesh Peering Confirm. While the
+ * standard does not state the same about IGTKdata, that same constraint
+ * needs to apply for it. It makes no sense to include the keys in Mesh
+ * Peering Close frames either, so while the standard does not seem to
+ * have a shall statement for these, they are described without
+ * mentioning GTKdata.
+ *
+ * An earlier implementation used to add GTKdata to both Mesh Peering
+ * Open and Mesh Peering Confirm frames, so ignore the possibly present
+ * GTKdata frame without rejecting the frame as a backwards
+ * compatibility mechanism.
+ */
+ if (cat[1] != PLINK_OPEN) {
+ if (end > pos) {
+ wpa_hexdump_key(MSG_DEBUG,
+ "mesh: Ignore unexpected GTKdata(etc.) fields in the end of AMPE element in Mesh Peering Confirm/Close",
+ pos, end - pos);
+ }
+ goto free;
+ }
+
+ /*
* GTKdata[variable]:
* MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
*/
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 8c5af5e..cb8df66 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -6632,6 +6632,12 @@
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (wpa_s->p2p_lo_started) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Cannot start P2P listen, it is offloaded");
+ return -1;
+ }
+
wpa_supplicant_cancel_sched_scan(wpa_s);
wpas_p2p_clear_pending_action_tx(wpa_s);
@@ -6705,7 +6711,7 @@
return 0;
switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
- ie, ie_len, rx_freq)) {
+ ie, ie_len, rx_freq, wpa_s->p2p_lo_started)) {
case P2P_PREQ_NOT_P2P:
wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
ssi_signal);
@@ -9206,3 +9212,86 @@
wpa_s->ap_iface->bss[0]->p2p_group = NULL;
wpas_p2p_group_deinit(wpa_s);
}
+
+
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ u8 *device_types;
+ size_t dev_types_len;
+ struct wpabuf *buf;
+ int ret;
+
+ if (wpa_s->p2p_lo_started) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P Listen offload is already started");
+ return 0;
+ }
+
+ if (wpa_s->global->p2p == NULL ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "P2P: Listen offload not supported");
+ return -1;
+ }
+
+ if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_ERROR, "P2P: Input channel not supported: %u",
+ freq);
+ return -1;
+ }
+
+ /* Get device type */
+ dev_types_len = (wpa_s->conf->num_sec_device_types + 1) *
+ WPS_DEV_TYPE_LEN;
+ device_types = os_malloc(dev_types_len);
+ if (!device_types)
+ return -1;
+ os_memcpy(device_types, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN);
+ os_memcpy(&device_types[WPS_DEV_TYPE_LEN], wpa_s->conf->sec_device_type,
+ wpa_s->conf->num_sec_device_types * WPS_DEV_TYPE_LEN);
+
+ /* Get Probe Response IE(s) */
+ buf = p2p_build_probe_resp_template(p2p, freq);
+ if (!buf) {
+ os_free(device_types);
+ return -1;
+ }
+
+ ret = wpa_drv_p2p_lo_start(wpa_s, freq, period, interval, count,
+ device_types, dev_types_len,
+ wpabuf_mhead_u8(buf), wpabuf_len(buf));
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to start P2P listen offload");
+
+ os_free(device_types);
+ wpabuf_free(buf);
+
+ if (ret == 0) {
+ wpa_s->p2p_lo_started = 1;
+
+ /* Stop current P2P listen if any */
+ wpas_stop_listen(wpa_s);
+ }
+
+ return ret;
+}
+
+
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+ int ret;
+
+ if (!wpa_s->p2p_lo_started)
+ return 0;
+
+ ret = wpa_drv_p2p_lo_stop(wpa_s);
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to stop P2P listen offload");
+
+ wpa_s->p2p_lo_started = 0;
+ return ret;
+}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 6a770d2..63910d1 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -207,6 +207,10 @@
void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count);
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
#else /* CONFIG_P2P */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 6ade9af..119da28 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -588,6 +588,12 @@
unsigned int i;
struct wpa_ssid *ssid;
+ /*
+ * For devices with max_ssids greater than 1, leave the last slot empty
+ * for adding the wildcard scan entry.
+ */
+ max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids;
+
for (i = 0; i < wpa_s->scan_id_count; i++) {
unsigned int j;
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 3a8f5b1..61fd3b2 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1585,8 +1585,10 @@
nbuf = os_realloc_array(wpa_s->sme.sa_query_trans_id,
wpa_s->sme.sa_query_count + 1,
WLAN_SA_QUERY_TR_ID_LEN);
- if (nbuf == NULL)
+ if (nbuf == NULL) {
+ sme_stop_sa_query(wpa_s);
return;
+ }
if (wpa_s->sme.sa_query_count == 0) {
/* Starting a new SA Query procedure */
os_get_reltime(&wpa_s->sme.sa_query_start);
@@ -1597,6 +1599,7 @@
if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
wpa_printf(MSG_DEBUG, "Could not generate SA Query ID");
+ sme_stop_sa_query(wpa_s);
return;
}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 53036ae..7012dfb 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -711,6 +711,13 @@
}
+static int wpa_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
@@ -2892,6 +2899,20 @@
}
+static int wpa_cli_cmd_p2p_lo_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_LO_START", 4, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_lo_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_LO_STOP", 0, argc, argv);
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -2949,6 +2970,9 @@
{ "get", wpa_cli_cmd_get, wpa_cli_complete_get,
cli_cmd_flag_none,
"<name> = get information" },
+ { "driver_flags", wpa_cli_cmd_driver_flags, NULL,
+ cli_cmd_flag_none,
+ "= list driver flags" },
{ "logon", wpa_cli_cmd_logon, NULL,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logon" },
@@ -3477,6 +3501,12 @@
{ "get_pref_freq_list", wpa_cli_cmd_get_pref_freq_list, NULL,
cli_cmd_flag_none,
"<interface type> = retrieve preferred freq list for the specified interface type" },
+ { "p2p_lo_start", wpa_cli_cmd_p2p_lo_start, NULL,
+ cli_cmd_flag_none,
+ "<freq> <period> <interval> <count> = start P2P listen offload" },
+ { "p2p_lo_stop", wpa_cli_cmd_p2p_lo_stop, NULL,
+ cli_cmd_flag_none,
+ "= stop P2P listen offload" },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 6999bbb..7ed7efa 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1873,6 +1873,13 @@
if (!mode)
return;
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht) {
+ freq->ht_enabled = 0;
+ return;
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
freq->ht_enabled = ht_supported(mode);
if (!freq->ht_enabled)
return;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index e45f662..dd6a60d 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -893,6 +893,7 @@
unsigned int p2p_go_max_oper_chwidth;
unsigned int p2p_go_vht_center_freq2;
+ int p2p_lo_started;
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;