diff options
| author | Anjaneedevi Kapparapu <akappa@codeaurora.org> | 2016-12-09 14:46:54 +0530 |
|---|---|---|
| committer | Anjaneedevi Kapparapu <akappa@codeaurora.org> | 2016-12-09 14:49:17 +0530 |
| commit | 18125eccf2482bf202b7a8e7839e33f089ed3469 (patch) | |
| tree | 146eca9e2aece6d74a0bb2858cf1aa3c01077d2b | |
| parent | ca79e23a75c92f0036eef4297a78a73630883a07 (diff) | |
| parent | 2bcbaa45580724f013ad6611d2af001d0a16c98d (diff) | |
| download | android_external_wpa_supplicant_8-18125eccf2482bf202b7a8e7839e33f089ed3469.tar.gz android_external_wpa_supplicant_8-18125eccf2482bf202b7a8e7839e33f089ed3469.tar.bz2 android_external_wpa_supplicant_8-18125eccf2482bf202b7a8e7839e33f089ed3469.zip | |
To Backport the N-Mr1 Changes
To Backport the N-Mr1 Changes
Merge remote-tracking branch 'origin/wlan-aosp-service.lnx.2.0.c1-rel' into wlan-aosp-service.lnx.2.0.c1-dev
* origin/wlan-aosp-service.lnx.2.0.c1-rel:
Update channel information after channel switch
Restart PNO/sched_scan on channel list update.
Share a common helper function for restarting sched_scan.
wpa_supplicant: Cancel sched_scan on SELECT_NETWORK initiated scan
nl80211: Allow TDLS trigger modes to be configured to the host driver
QCA vendor command to configure the TDLS behavior in the host driver
Do not exceed scan ssid max size advertised by driver
P2P: Check if the pref_freq reported by the driver supports P2P
EAP-Proxy: Consider EAP-AKA' in SelectedMethod of Status command.
MBO: Add support to send ANQP request to get cellular preference
MBO: Do not add reason_detail in non_pref_chan attr (STA)
WNM: Add testing option to reject BSS Transition Management Request
MBO: Add support to ignore association disallowed set by AP
MBO: Remove unused assignment
MBO: Improve supported operating class generation
MBO: Mark verify_channel() static
DO NOT MERGE Dont exceed scan ssid max size advertised by driver
Fix use-after-free in qca_nl80211_get_features
nl80211: Register for only for specific Action frames in AP mode [DO NOT MERGE]
DO NOT MERGE ANYWHERE Fix max number of sched scan SSIDs based on driver capability
Change-Id: If55136276bd00b829422e81a2dd4715da7c1b56e
CRs-Fixed: 1099470
| -rw-r--r-- | src/common/ieee802_11_defs.h | 4 | ||||
| -rw-r--r-- | src/common/qca-vendor.h | 93 | ||||
| -rw-r--r-- | src/drivers/driver.h | 10 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.c | 102 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211_event.c | 1 | ||||
| -rw-r--r-- | src/eap_peer/eap_proxy_qmi.c | 16 | ||||
| -rw-r--r-- | wpa_supplicant/ctrl_iface.c | 34 | ||||
| -rw-r--r-- | wpa_supplicant/driver_i.h | 9 | ||||
| -rw-r--r-- | wpa_supplicant/events.c | 23 | ||||
| -rw-r--r-- | wpa_supplicant/interworking.c | 31 | ||||
| -rw-r--r-- | wpa_supplicant/interworking.h | 3 | ||||
| -rw-r--r-- | wpa_supplicant/mbo.c | 127 | ||||
| -rw-r--r-- | wpa_supplicant/p2p_supplicant.c | 6 | ||||
| -rw-r--r-- | wpa_supplicant/scan.c | 33 | ||||
| -rw-r--r-- | wpa_supplicant/scan.h | 2 | ||||
| -rw-r--r-- | wpa_supplicant/wnm_sta.c | 13 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant.c | 1 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant.conf | 6 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant_i.h | 5 |
19 files changed, 444 insertions, 75 deletions
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index e1a8ef78..6912320c 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1116,6 +1116,10 @@ enum wfa_wnm_notif_subelem_id { WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA = 3, }; +/* MBO v0.0_r25, 4.3: MBO ANQP-elements */ +#define MBO_ANQP_OUI_TYPE 0x12 +#define MBO_ANQP_SUBTYPE_CELL_CONN_PREF 1 + /* Wi-Fi Direct (P2P) */ #define P2P_OUI_TYPE 9 diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index d3683728..36bacc0f 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -188,6 +188,10 @@ enum qca_radiotap_vendor_ids { * * @QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI: Get antenna RSSI value for a * specific chain. + * + * @QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS: Configure the TDLS behavior + * in the host driver. The different TDLS configurations are defined + * by the attributes in enum qca_wlan_vendor_attr_tdls_configuration. */ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, @@ -288,6 +292,7 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT = 136, QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST = 137, QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI = 138, + QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS = 143, }; @@ -1380,4 +1385,92 @@ enum qca_wlan_vendor_attr_encryption_test { QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST - 1 }; +/** + * enum qca_wlan_vendor_attr_tdls_configuration - Attributes for + * TDLS configuration to the host driver. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE: Configure the TDLS trigger + * mode in the host driver. enum qca_wlan_vendor_tdls_trigger_mode + * represents the different TDLS trigger modes. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD: Duration (u32) within + * which QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD number + * of packets shall meet the criteria for implicit TDLS setup. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD: Number (u32) of Tx/Rx packets + * within a duration QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD + * to initiate a TDLS setup. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD: Time (u32) to initiate + * a TDLS Discovery to the peer. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT: Max number (u32) of + * discovery attempts to know the TDLS capability of the peer. A peer is + * marked as TDLS not capable if there is no response for all the attempts. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT: Represents a duration (u32) + * within which QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD + * number of TX / RX frames meet the criteria for TDLS teardown. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD: Minimum number (u32) + * of Tx/Rx packets within a duration + * QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT to tear down a TDLS link. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD: Threshold + * corresponding to the RSSI of the peer below which a TDLS setup is + * triggered. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD: Threshold + * corresponding to the RSSI of the peer above which a TDLS teardown is + * triggered. + */ +enum qca_wlan_vendor_attr_tdls_configuration { + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE = 1, + + /* Attributes configuring the TDLS Implicit Trigger */ + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD = 2, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD = 3, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD = 4, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT = 5, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT = 6, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD = 7, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD = 8, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD = 9, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_tdls_trigger_mode: Represents the TDLS trigger mode in + * the driver + * + * The following are the different values for + * QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE. + * + * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: The trigger to initiate/teardown + * the TDLS connection to a respective peer comes from the user space. + * wpa_supplicant provides the commands TDLS_SETUP, TDLS_TEARDOWN, + * TDLS_DISCOVER to do this. + * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: Host driver triggers this TDLS + * setup/teardown to the eligible peer once the configured criteria + * (such as TX/RX threshold, RSSI) is met. The attributes + * in QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IMPLICIT_PARAMS correspond to + * the different configuration criteria for the TDLS trigger from the + * host driver. + * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: Enables the driver to trigger + * the TDLS setup / teardown through the implicit mode only to the + * configured MAC addresses (wpa_supplicant, with tdls_external_control=1, + * configures the MAC address through TDLS_SETUP / TDLS_TEARDOWN commands). + * External mode works on top of the implicit mode. Thus the host driver + * is expected to configure in TDLS Implicit mode too to operate in + * External mode. + * Configuring External mode alone without Implicit mode is invalid. + * + * All the above implementations work as expected only when the host driver + * advertises the capability WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP - representing + * that the TDLS message exchange is not internal to the host driver, but + * depends on wpa_supplicant to do the message exchange. + */ +enum qca_wlan_vendor_tdls_trigger_mode { + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT = 1 << 0, + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT = 1 << 1, + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL = 1 << 2, +}; + #endif /* QCA_VENDOR_H */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 3aecf16e..656b5bc7 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -3595,6 +3595,16 @@ struct wpa_driver_ops { */ int (*set_default_scan_ies)(void *priv, const u8 *ies, size_t ies_len); + /** + * set_tdls_mode - Set TDLS trigger mode to the host driver + * @priv: Private driver interface data + * @tdls_external_control: Represents if TDLS external trigger control + * mode is enabled/disabled. + * + * This optional callback can be used to configure the TDLS external + * trigger control mode to the host driver. + */ + int (*set_tdls_mode)(void *priv, int tdls_external_control); }; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index fd9cd01c..8bf049b8 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2050,6 +2050,49 @@ static int nl80211_register_spurious_class3(struct i802_bss *bss) } +static int nl80211_action_subscribe_ap(struct i802_bss *bss) +{ + int ret = 0; + + /* Public Action frames */ + if (nl80211_register_action_frame(bss, (u8 *) "\x04", 1) < 0) + ret = -1; + /* RRM Measurement Report */ + if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0) + ret = -1; + /* RRM Neighbor Report Request */ + if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0) + ret = -1; + /* FT Action frames */ + if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0) + ret = -1; +#ifdef CONFIG_IEEE80211W + /* SA Query */ + if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0) + ret = -1; +#endif /* CONFIG_IEEE80211W */ + /* Protected Dual of Public Action */ + if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0) + ret = -1; + /* WNM */ + if (nl80211_register_action_frame(bss, (u8 *) "\x0a", 1) < 0) + ret = -1; + /* WMM */ + if (nl80211_register_action_frame(bss, (u8 *) "\x11", 1) < 0) + ret = -1; +#ifdef CONFIG_FST + /* FST Action frames */ + if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0) + ret = -1; +#endif /* CONFIG_FST */ + /* Vendor-specific */ + if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0) + ret = -1; + + return ret; +} + + static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss) { static const int stypes[] = { @@ -2058,7 +2101,6 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss) WLAN_FC_STYPE_REASSOC_REQ, WLAN_FC_STYPE_DISASSOC, WLAN_FC_STYPE_DEAUTH, - WLAN_FC_STYPE_ACTION, WLAN_FC_STYPE_PROBE_REQ, /* Beacon doesn't work as mac80211 doesn't currently allow * it, but it wouldn't really be the right thing anyway as @@ -2083,6 +2125,9 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss) } } + if (nl80211_action_subscribe_ap(bss)) + goto out_err; + if (nl80211_register_spurious_class3(bss)) goto out_err; @@ -2105,10 +2150,7 @@ static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss) wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP " "handle %p (device SME)", bss->nl_mgmt); - if (nl80211_register_frame(bss, bss->nl_mgmt, - (WLAN_FC_TYPE_MGMT << 2) | - (WLAN_FC_STYPE_ACTION << 4), - NULL, 0) < 0) + if (nl80211_action_subscribe_ap(bss)) goto out_err; nl80211_mgmt_handle_register_eloop(bss); @@ -9137,6 +9179,55 @@ static int nl80211_p2p_lo_stop(void *priv) return send_and_recv_msgs(drv, msg, NULL, NULL); } + +static int nl80211_set_tdls_mode(void *priv, int tdls_external_control) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *params; + int ret; + u32 tdls_mode; + + wpa_printf(MSG_DEBUG, + "nl80211: Set TDKS mode: tdls_external_control=%d", + tdls_external_control); + + if (tdls_external_control == 1) + tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT | + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL; + else + tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT; + + 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_CONFIGURE_TDLS)) + goto fail; + + params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); + if (!params) + goto fail; + + if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE, + tdls_mode)) + goto fail; + + nla_nest_end(msg, params); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_ERROR, + "nl80211: Set TDLS mode failed: ret=%d (%s)", + ret, strerror(-ret)); + goto fail; + } + return 0; +fail: + nlmsg_free(msg); + return -1; +} #endif /* CONFIG_DRIVER_NL80211_QCA */ static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type, @@ -9290,6 +9381,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .p2p_lo_start = nl80211_p2p_lo_start, .p2p_lo_stop = nl80211_p2p_lo_stop, .set_default_scan_ies = nl80211_set_default_scan_ies, + .set_tdls_mode = nl80211_set_tdls_mode, #endif /* CONFIG_DRIVER_NL80211_QCA */ .get_ext_capab = nl80211_get_ext_capab, }; diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 610ab4b1..e1489f13 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -516,6 +516,7 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, data.ch_switch.cf2 = nla_get_u32(cf2); bss->freq = data.ch_switch.freq; + drv->assoc_freq = data.ch_switch.freq; wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data); } diff --git a/src/eap_peer/eap_proxy_qmi.c b/src/eap_peer/eap_proxy_qmi.c index 0d493723..bd132cff 100644 --- a/src/eap_peer/eap_proxy_qmi.c +++ b/src/eap_peer/eap_proxy_qmi.c @@ -2050,12 +2050,16 @@ int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen, return 0; if (sm->eap_type != EAP_TYPE_NONE) { - char name[8] = "Unknown"; - - if (sm->eap_type == EAP_TYPE_SIM) - os_strlcpy(name, "SIM", 4); - else if (sm->eap_type == EAP_TYPE_AKA) - os_strlcpy(name, "AKA", 4); + char name[8]; + + if (sm->eap_type == EAP_TYPE_SIM) + os_strlcpy(name, "SIM", 4); + else if (sm->eap_type == EAP_TYPE_AKA) + os_strlcpy(name, "AKA", 4); + else if (sm->eap_type == EAP_TYPE_AKA_PRIME) + os_strlcpy(name, "AKA'", 5); + else + os_strlcpy(name, "Unknown", 8); ret = os_snprintf(buf + len, buflen - len, "selectedMethod=%d (EAP-%s)\n", diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 6154afee..9ff6a4a9 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -484,6 +484,10 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wpa_s->test_failure = atoi(value); } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) { wpa_s->p2p_go_csa_on_inv = !!atoi(value); + } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) { + wpa_s->ignore_assoc_disallow = !!atoi(value); + } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) { + wpa_s->reject_btm_req_reason = atoi(value); #endif /* CONFIG_TESTING_OPTIONS */ #ifndef CONFIG_NO_CONFIG_BLOBS } else if (os_strcmp(cmd, "blob") == 0) { @@ -497,6 +501,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) { wpas_mbo_update_cell_capa(wpa_s, atoi(value)); #endif /* CONFIG_MBO */ + } else if (os_strcasecmp(cmd, "tdls_trigger_control") == 0) { + ret = wpa_drv_set_tdls_mode(wpa_s, atoi(value)); } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); @@ -6384,6 +6390,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) u16 id[MAX_ANQP_INFO_ID]; size_t num_id = 0; u32 subtypes = 0; + int get_cell_pref = 0; used = hwaddr_aton2(dst, dst_addr); if (used < 0) @@ -6401,6 +6408,15 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) #else /* CONFIG_HS20 */ return -1; #endif /* CONFIG_HS20 */ + } else if (os_strncmp(pos, "mbo:", 4) == 0) { +#ifdef CONFIG_MBO + int num = atoi(pos + 4); + if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF) + return -1; + get_cell_pref = 1; +#else /* CONFIG_MBO */ + return -1; +#endif /* CONFIG_MBO */ } else { id[num_id] = atoi(pos); if (id[num_id]) @@ -6415,7 +6431,8 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) if (num_id == 0) return -1; - return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes); + return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes, + get_cell_pref); } @@ -7179,6 +7196,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->extra_roc_dur = 0; wpa_s->test_failure = WPAS_TEST_FAILURE_NONE; wpa_s->p2p_go_csa_on_inv = 0; + wpa_s->ignore_assoc_disallow = 0; + wpa_s->reject_btm_req_reason = 0; wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL); #endif /* CONFIG_TESTING_OPTIONS */ @@ -8357,10 +8376,7 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, } } else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) { - /* simulate timeout to restart the sched scan */ - wpa_s->sched_scan_timed_out = 1; - wpa_s->prev_sched_ssid = NULL; - wpa_supplicant_cancel_sched_scan(wpa_s); + wpas_scan_restart_sched_scan(wpa_s); } return 0; } @@ -8386,12 +8402,8 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN, addr, mask); - if (wpa_s->sched_scanning && !wpa_s->pno) { - /* simulate timeout to restart the sched scan */ - wpa_s->sched_scan_timed_out = 1; - wpa_s->prev_sched_ssid = NULL; - wpa_supplicant_cancel_sched_scan(wpa_s); - } + if (wpa_s->sched_scanning && !wpa_s->pno) + wpas_scan_restart_sched_scan(wpa_s); } if (type & MAC_ADDR_RAND_PNO) { diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 869b705f..26e86225 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -959,4 +959,13 @@ static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s, return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len); } +static inline int wpa_drv_set_tdls_mode(struct wpa_supplicant *wpa_s, + int tdls_external_control) +{ + if (!wpa_s->driver->set_tdls_mode) + return -1; + return wpa_s->driver->set_tdls_mode(wpa_s->drv_priv, + tdls_external_control); +} + #endif /* DRIVER_I_H */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index fed9aca6..cb51e95e 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1078,6 +1078,10 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, continue; } #ifdef CONFIG_MBO +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->ignore_assoc_disallow) + goto skip_assoc_disallow; +#endif /* CONFIG_TESTING_OPTIONS */ assoc_disallow = wpas_mbo_get_bss_attr( bss, MBO_ATTR_ID_ASSOC_DISALLOW); if (assoc_disallow && assoc_disallow[1] >= 1) { @@ -1092,6 +1096,9 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, " skip - MBO retry delay has not passed yet"); continue; } +#ifdef CONFIG_TESTING_OPTIONS + skip_assoc_disallow: +#endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_MBO */ /* Matching configuration found */ @@ -3183,14 +3190,16 @@ static void wpa_supplicant_update_channel_list( free_hw_features(ifs); ifs->hw.modes = wpa_drv_get_hw_feature_data( ifs, &ifs->hw.num_modes, &ifs->hw.flags); - } - /* Restart sched_scan with updated channel list */ - if (wpa_s->sched_scanning) { - wpa_dbg(wpa_s, MSG_DEBUG, - "Channel list changed restart sched scan."); - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_supplicant_req_scan(wpa_s, 0, 0); + /* Restart PNO/sched_scan with updated channel list */ + if (ifs->pno) { + wpas_stop_pno(ifs); + wpas_start_pno(ifs); + } else if (ifs->sched_scanning && !ifs->pno_sched_pending) { + wpa_dbg(ifs, MSG_DEBUG, + "Channel list changed - restart sched_scan"); + wpas_scan_restart_sched_scan(ifs); + } } wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DRIVER); diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 589ee57b..ef8747e0 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -2702,10 +2702,11 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s) int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, - u16 info_ids[], size_t num_ids, u32 subtypes) + u16 info_ids[], size_t num_ids, u32 subtypes, + int get_cell_pref) { struct wpabuf *buf; - struct wpabuf *hs20_buf = NULL; + struct wpabuf *extra_buf = NULL; int ret = 0; int freq; struct wpa_bss *bss; @@ -2728,15 +2729,31 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, #ifdef CONFIG_HS20 if (subtypes != 0) { - hs20_buf = wpabuf_alloc(100); - if (hs20_buf == NULL) + extra_buf = wpabuf_alloc(100); + if (extra_buf == NULL) return -1; - hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf); + hs20_put_anqp_req(subtypes, NULL, 0, extra_buf); } #endif /* CONFIG_HS20 */ - buf = anqp_build_req(info_ids, num_ids, hs20_buf); - wpabuf_free(hs20_buf); +#ifdef CONFIG_MBO + if (get_cell_pref) { + struct wpabuf *mbo; + + mbo = mbo_build_anqp_buf(wpa_s, bss); + if (mbo) { + if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) { + wpabuf_free(extra_buf); + return -1; + } + wpabuf_put_buf(extra_buf, mbo); + wpabuf_free(mbo); + } + } +#endif /* CONFIG_MBO */ + + buf = anqp_build_req(info_ids, num_ids, extra_buf); + wpabuf_free(extra_buf); if (buf == NULL) return -1; diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h index 3743dc00..3d222926 100644 --- a/wpa_supplicant/interworking.h +++ b/wpa_supplicant/interworking.h @@ -12,7 +12,8 @@ enum gas_query_result; int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, - u16 info_ids[], size_t num_ids, u32 subtypes); + u16 info_ids[], size_t num_ids, u32 subtypes, + int get_cell_pref); void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c index 1154ab6d..7e049be3 100644 --- a/wpa_supplicant/mbo.c +++ b/wpa_supplicant/mbo.c @@ -14,6 +14,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" +#include "common/gas.h" #include "config.h" #include "wpa_supplicant_i.h" #include "driver_i.h" @@ -68,14 +69,13 @@ static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s, wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].preference); wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason); - wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason_detail); } static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s, struct wpabuf *mbo, u8 start, u8 end) { - size_t size = end - start + 4; + size_t size = end - start + 3; if (size + 2 > wpabuf_tailroom(mbo)) return; @@ -100,7 +100,7 @@ static void wpas_mbo_non_pref_chan_subelement(struct wpa_supplicant *wpa_s, struct wpabuf *mbo, u8 start, u8 end) { - size_t size = end - start + 8; + size_t size = end - start + 7; if (size + 2 > wpabuf_tailroom(mbo)) return; @@ -131,7 +131,6 @@ static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s, if (!non_pref || non_pref->oper_class != start_pref->oper_class || non_pref->reason != start_pref->reason || - non_pref->reason_detail != start_pref->reason_detail || non_pref->preference != start_pref->preference) { if (subelement) wpas_mbo_non_pref_chan_subelement(wpa_s, mbo, @@ -250,9 +249,9 @@ static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a, * * In MBO IE non-preferred channel subelement we can put many channels in an * attribute if they are in the same operating class and have the same - * preference, reason, and reason detail. To make it easy for the functions that - * build the IE attributes and WNM Request subelements, save the channels sorted - * by their oper_class, reason, and reason_detail. + * preference and reason. To make it easy for the functions that build + * the IE attributes and WNM Request subelements, save the channels sorted + * by their oper_class and reason. */ static int wpa_non_pref_chan_cmp(const void *_a, const void *_b) { @@ -262,8 +261,6 @@ static int wpa_non_pref_chan_cmp(const void *_a, const void *_b) return a->oper_class - b->oper_class; if (a->reason != b->reason) return a->reason - b->reason; - if (a->reason_detail != b->reason_detail) - return a->reason_detail - b->reason_detail; return a->preference - b->preference; } @@ -298,7 +295,6 @@ int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, unsigned int _chan; unsigned int _preference; unsigned int _reason; - unsigned int _reason_detail; if (num == size) { size = size ? size * 2 : 1; @@ -314,13 +310,11 @@ int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, chan = &chans[num]; - ret = sscanf(token, "%u:%u:%u:%u:%u", &_oper_class, - &_chan, &_preference, &_reason, - &_reason_detail); - if ((ret != 4 && ret != 5) || + ret = sscanf(token, "%u:%u:%u:%u", &_oper_class, + &_chan, &_preference, &_reason); + if (ret != 4 || _oper_class > 255 || _chan > 255 || - _preference > 255 || _reason > 65535 || - (ret == 5 && _reason_detail > 255)) { + _preference > 255 || _reason > 65535 ) { wpa_printf(MSG_ERROR, "Invalid non-pref chan input %s", token); goto fail; @@ -329,7 +323,6 @@ int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, chan->chan = _chan; chan->preference = _preference; chan->reason = _reason; - chan->reason_detail = ret == 4 ? 0 : _reason_detail; if (wpas_mbo_validate_non_pref_chan(chan->oper_class, chan->chan, chan->reason)) { @@ -517,8 +510,8 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode, } -enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel, - u8 bw) +static enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, + u8 channel, u8 bw) { unsigned int flag = 0; enum chan_allowed res, res2; @@ -533,9 +526,26 @@ enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel, 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) @@ -551,38 +561,63 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s, 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; + /* 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 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; } @@ -771,3 +806,31 @@ void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa) wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7); wpa_supplicant_set_default_scan_ies(wpa_s); } + + +struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) +{ + struct wpabuf *anqp_buf; + u8 *len_pos; + + if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) { + wpa_printf(MSG_INFO, "MBO: " MACSTR + " does not support MBO - cannot request MBO ANQP elements from it", + MAC2STR(bss->bssid)); + return NULL; + } + + anqp_buf = wpabuf_alloc(10); + if (!anqp_buf) + return NULL; + + len_pos = gas_anqp_add_element(anqp_buf, ANQP_VENDOR_SPECIFIC); + wpabuf_put_be24(anqp_buf, OUI_WFA); + wpabuf_put_u8(anqp_buf, MBO_ANQP_OUI_TYPE); + + wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF); + gas_anqp_set_element_len(anqp_buf, len_pos); + + return anqp_buf; +} diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 527d1595..14237abb 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -5248,8 +5248,10 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, if (!res && max_pref_freq > 0) { *num_pref_freq = max_pref_freq; i = 0; - while (wpas_p2p_disallowed_freq(wpa_s->global, - pref_freq_list[i]) && + while ((!p2p_supported_freq(wpa_s->global->p2p, + pref_freq_list[i]) || + wpas_p2p_disallowed_freq(wpa_s->global, + pref_freq_list[i])) && i < *num_pref_freq) { wpa_printf(MSG_DEBUG, "P2P: preferred_freq_list[%d]=%d is disallowed", diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 4b450d7b..8c1384a7 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -615,6 +615,11 @@ static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s, { 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 : max_ssids - 1; /* * For devices with max_ssids greater than 1, leave the last slot empty @@ -2730,3 +2735,31 @@ fail: wpa_printf(MSG_ERROR, "invalid scan plans list"); return -1; } + + +/** + * wpas_scan_reset_sched_scan - Reset sched_scan state + * @wpa_s: Pointer to wpa_supplicant data + * + * This function is used to cancel a running scheduled scan and to reset an + * internal scan state to continue with a regular scan on the following + * wpa_supplicant_req_scan() calls. + */ +void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s) +{ + wpa_s->normal_scans = 0; + if (wpa_s->sched_scanning) { + wpa_s->sched_scan_timed_out = 0; + wpa_s->prev_sched_ssid = NULL; + wpa_supplicant_cancel_sched_scan(wpa_s); + } +} + + +void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s) +{ + /* simulate timeout to restart the sched scan */ + wpa_s->sched_scan_timed_out = 1; + wpa_s->prev_sched_ssid = NULL; + wpa_supplicant_cancel_sched_scan(wpa_s); +} diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index a734148a..46219f6e 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -47,6 +47,8 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src); void wpa_scan_free_params(struct wpa_driver_scan_params *params); int wpas_start_pno(struct wpa_supplicant *wpa_s); int wpas_stop_pno(struct wpa_supplicant *wpa_s); +void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s); +void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s); void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s, unsigned int type); diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 520b0095..dc20ee00 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -1159,6 +1159,19 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_s->wnm_dialog_token, wpa_s->wnm_mode, wpa_s->wnm_dissoc_timer, valid_int); +#if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS) + if (wpa_s->reject_btm_req_reason) { + wpa_printf(MSG_INFO, + "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", + wpa_s->reject_btm_req_reason); + wnm_send_bss_transition_mgmt_resp(wpa_s, + wpa_s->wnm_dialog_token, + wpa_s->reject_btm_req_reason, + 0, NULL); + return; + } +#endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ + pos += 5; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index ef1c63fd..5bad4b55 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2893,6 +2893,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, if (wpa_s->connect_without_scan || wpa_supplicant_fast_associate(wpa_s) != 1) { wpa_s->scan_req = NORMAL_SCAN_REQ; + wpas_scan_reset_sched_scan(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0); } diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index ff3aa841..b72608a9 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -649,11 +649,11 @@ fast_reauth=1 # Multi Band Operation (MBO) non-preferred channels # A space delimited list of non-preferred channels where each channel is a colon -# delimited list of values. Reason detail is optional. +# delimited list of values. # Format: -# non_pref_chan=<oper_class>:<chan>:<preference>:<reason>[:reason_detail] +# non_pref_chan=<oper_class>:<chan>:<preference>:<reason> # Example: -# non_pref_chan="81:5:10:2:0 81:1:0:2:0 81:9:0:2" +# non_pref_chan="81:5:10:2 81:1:0:2 81:9:0:2" # MBO Cellular Data Capabilities # 1 = Cellular data connection available diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index b07255ef..af5d6590 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1028,7 +1028,9 @@ struct wpa_supplicant { struct l2_packet_data *l2_test; unsigned int extra_roc_dur; enum wpa_supplicant_test_failure test_failure; + unsigned int reject_btm_req_reason; unsigned int p2p_go_csa_on_inv:1; + unsigned int ignore_assoc_disallow:1; #endif /* CONFIG_TESTING_OPTIONS */ struct wmm_ac_assoc_data *wmm_ac_assoc_info; @@ -1052,7 +1054,6 @@ struct wpa_supplicant { enum mbo_non_pref_chan_reason reason; u8 oper_class; u8 chan; - u8 reason_detail; u8 preference; } *non_pref_chan; size_t non_pref_chan_num; @@ -1193,6 +1194,8 @@ size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos, size_t len, enum mbo_transition_reject_reason reason); void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa); +struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss); /** * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response |
