Cumulative patch from commit ea18024d78bde140fb8f74d216d757816bfd6e9b
ea18024 dbus: Add PropertiesChanged signal to Peer object
36716ee P2P: Add a utility function to run a method on every known peer
bf03566 dbus: Remove GroupMember object type and use Peer instead
17a37d7 dbus: Add a Groups property to a Peer object on which it belongs
6f04642 P2P: Add utility functions to get GO/client interface
c6386e5 P2P Add a utility to run a callback on all available groups
8e76f48 P2P: Add a utility function to get the group configuration
37d8a27 TDLS: Clean up add/set peer operations
bcd2baa TDLS: Tear down connection on malformed Setup Confirm
8190540 TDLS: Abort local setup when failing to add STA
1dce7a2 TDLS: Update peer STA as soon as full peer info is available
819c943 TDLS: Remove peer from global peer-list on free
5841958 hostapd: Use channel switch fallback on error
8974620 hostapd: Perform multi-BSS CSA for DFS properly
ccac7c6 hostapd: Make chan_switch command per-interface not per-BSS
6782b68 hostapd: Move CSA parameters to hostapd_data
1de809e eapol_test: Fix -R option to not replace -s option value
3c5d34e Change channel before IBSS associations
ebffdbc nl80211: Refactor mode switch logic
Change-Id: I1cbdc4dce586ec69f693b3b04eb340a5332f6b40
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 73dffe2..b3b6149 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -265,18 +265,18 @@
{
u8 chan;
- if (!hapd->iface->cs_freq_params.freq)
+ if (!hapd->cs_freq_params.freq)
return eid;
- if (ieee80211_freq_to_chan(hapd->iface->cs_freq_params.freq, &chan) ==
+ if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) ==
NUM_HOSTAPD_MODES)
return eid;
*eid++ = WLAN_EID_CHANNEL_SWITCH;
*eid++ = 3;
- *eid++ = hapd->iface->cs_block_tx;
+ *eid++ = hapd->cs_block_tx;
*eid++ = chan;
- *eid++ = hapd->iface->cs_count;
+ *eid++ = hapd->cs_count;
return eid;
}
@@ -286,12 +286,12 @@
{
u8 sec_ch;
- if (!hapd->iface->cs_freq_params.sec_channel_offset)
+ if (!hapd->cs_freq_params.sec_channel_offset)
return eid;
- if (hapd->iface->cs_freq_params.sec_channel_offset == -1)
+ if (hapd->cs_freq_params.sec_channel_offset == -1)
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
- else if (hapd->iface->cs_freq_params.sec_channel_offset == 1)
+ else if (hapd->cs_freq_params.sec_channel_offset == 1)
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
else
return eid;
@@ -409,7 +409,7 @@
pos = hostapd_eid_roaming_consortium(hapd, pos);
pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
- &hapd->iface->cs_c_off_proberesp);
+ &hapd->cs_c_off_proberesp);
#ifdef CONFIG_IEEE80211AC
pos = hostapd_eid_vht_capabilities(hapd, pos);
pos = hostapd_eid_vht_operation(hapd, pos);
@@ -824,7 +824,7 @@
tailpos = hostapd_eid_adv_proto(hapd, tailpos);
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
- &hapd->iface->cs_c_off_beacon);
+ &hapd->cs_c_off_beacon);
#ifdef CONFIG_IEEE80211AC
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
@@ -957,7 +957,7 @@
struct wpabuf *beacon, *proberesp, *assocresp;
int res, ret = -1;
- if (hapd->iface->csa_in_progress) {
+ if (hapd->csa_in_progress) {
wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
return -1;
}
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index c30f6d6..a11b2cf 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -756,6 +756,16 @@
}
+static int hostapd_csa_in_progress(struct hostapd_iface *iface)
+{
+ unsigned int i;
+ for (i = 0; i < iface->num_bss; i++)
+ if (iface->bss[i]->csa_in_progress)
+ return 1;
+ return 0;
+}
+
+
static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
@@ -764,15 +774,15 @@
u8 vht_oper_centr_freq_seg1_idx;
int skip_radar = 1;
struct csa_settings csa_settings;
- struct hostapd_data *hapd = iface->bss[0];
+ unsigned int i;
int err = 1;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
- iface->csa_in_progress ? "yes" : "no");
+ hostapd_csa_in_progress(iface) ? "yes" : "no");
/* Check if CSA in progress */
- if (iface->csa_in_progress)
+ if (hostapd_csa_in_progress(iface))
return 0;
/* Check if active CAC */
@@ -843,7 +853,12 @@
return err;
}
- err = hostapd_switch_channel(hapd, &csa_settings);
+ for (i = 0; i < iface->num_bss; i++) {
+ err = hostapd_switch_channel(iface->bss[i], &csa_settings);
+ if (err)
+ break;
+ }
+
if (err) {
wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
err);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index fb095ef..93804de 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -489,9 +489,10 @@
hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
- if (hapd->iface->csa_in_progress &&
- freq == hapd->iface->cs_freq_params.freq) {
+ if (hapd->csa_in_progress &&
+ freq == hapd->cs_freq_params.freq) {
hostapd_cleanup_cs_params(hapd);
+ ieee802_11_set_beacon(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d",
freq);
@@ -884,6 +885,20 @@
#ifdef NEED_AP_MLME
+static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
+{
+ wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
+ hapd->conf->iface);
+
+ if (hapd->csa_in_progress) {
+ wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
+ hapd->conf->iface);
+ hostapd_switch_channel_fallback(hapd->iface,
+ &hapd->cs_freq_params);
+ }
+}
+
+
static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
struct dfs_event *radar)
{
@@ -1071,6 +1086,9 @@
hostapd_event_get_survey(hapd, &data->survey_results);
break;
#ifdef NEED_AP_MLME
+ case EVENT_INTERFACE_UNAVAILABLE:
+ hostapd_event_iface_unavailable(hapd);
+ break;
case EVENT_DFS_RADAR_DETECTED:
if (!data)
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 4e09fa3..55b7ced 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -2175,13 +2175,12 @@
}
-static int hostapd_build_beacon_data(struct hostapd_iface *iface,
+static int hostapd_build_beacon_data(struct hostapd_data *hapd,
struct beacon_data *beacon)
{
struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
struct wpa_driver_ap_params params;
int ret;
- struct hostapd_data *hapd = iface->bss[0];
os_memset(beacon, 0, sizeof(*beacon));
ret = ieee802_11_build_ap_params(hapd, ¶ms);
@@ -2281,13 +2280,13 @@
if (!params->channel) {
/* check if the new channel is supported by hw */
- channel = hostapd_hw_get_channel(hapd, params->freq);
- if (!channel)
- return -1;
- } else {
- channel = params->channel;
+ params->channel = hostapd_hw_get_channel(hapd, params->freq);
}
+ channel = params->channel;
+ if (!channel)
+ return -1;
+
/* if a pointer to old_params is provided we save previous state */
if (old_params) {
old_params->channel = conf->channel;
@@ -2305,14 +2304,15 @@
}
-static int hostapd_fill_csa_settings(struct hostapd_iface *iface,
+static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
struct csa_settings *settings)
{
+ struct hostapd_iface *iface = hapd->iface;
struct hostapd_freq_params old_freq;
int ret;
os_memset(&old_freq, 0, sizeof(old_freq));
- if (!iface || !iface->freq || iface->csa_in_progress)
+ if (!iface || !iface->freq || hapd->csa_in_progress)
return -1;
ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
@@ -2321,7 +2321,7 @@
if (ret)
return ret;
- ret = hostapd_build_beacon_data(iface, &settings->beacon_after);
+ ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
/* change back the configuration */
hostapd_change_config_freq(iface->bss[0], iface->conf,
@@ -2331,18 +2331,18 @@
return ret;
/* set channel switch parameters for csa ie */
- iface->cs_freq_params = settings->freq_params;
- iface->cs_count = settings->cs_count;
- iface->cs_block_tx = settings->block_tx;
+ hapd->cs_freq_params = settings->freq_params;
+ hapd->cs_count = settings->cs_count;
+ hapd->cs_block_tx = settings->block_tx;
- ret = hostapd_build_beacon_data(iface, &settings->beacon_csa);
+ ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa);
if (ret) {
free_beacon_data(&settings->beacon_after);
return ret;
}
- settings->counter_offset_beacon = iface->cs_c_off_beacon;
- settings->counter_offset_presp = iface->cs_c_off_proberesp;
+ settings->counter_offset_beacon = hapd->cs_c_off_beacon;
+ settings->counter_offset_presp = hapd->cs_c_off_proberesp;
return 0;
}
@@ -2350,13 +2350,12 @@
void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
{
- os_memset(&hapd->iface->cs_freq_params, 0,
- sizeof(hapd->iface->cs_freq_params));
- hapd->iface->cs_count = 0;
- hapd->iface->cs_block_tx = 0;
- hapd->iface->cs_c_off_beacon = 0;
- hapd->iface->cs_c_off_proberesp = 0;
- hapd->iface->csa_in_progress = 0;
+ os_memset(&hapd->cs_freq_params, 0, sizeof(hapd->cs_freq_params));
+ hapd->cs_count = 0;
+ hapd->cs_block_tx = 0;
+ hapd->cs_c_off_beacon = 0;
+ hapd->cs_c_off_proberesp = 0;
+ hapd->csa_in_progress = 0;
}
@@ -2364,7 +2363,7 @@
struct csa_settings *settings)
{
int ret;
- ret = hostapd_fill_csa_settings(hapd->iface, settings);
+ ret = hostapd_fill_csa_settings(hapd, settings);
if (ret)
return ret;
@@ -2378,8 +2377,64 @@
return ret;
}
- hapd->iface->csa_in_progress = 1;
+ hapd->csa_in_progress = 1;
return 0;
}
+
+void
+hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ const struct hostapd_freq_params *freq_params)
+{
+ int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
+ unsigned int i;
+
+ wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
+
+ if (freq_params->center_freq1)
+ vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
+ if (freq_params->center_freq2)
+ vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
+
+ switch (freq_params->bandwidth) {
+ case 0:
+ case 20:
+ case 40:
+ vht_bw = VHT_CHANWIDTH_USE_HT;
+ break;
+ case 80:
+ if (freq_params->center_freq2)
+ vht_bw = VHT_CHANWIDTH_80P80MHZ;
+ else
+ vht_bw = VHT_CHANWIDTH_80MHZ;
+ break;
+ case 160:
+ vht_bw = VHT_CHANWIDTH_160MHZ;
+ break;
+ default:
+ wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
+ freq_params->bandwidth);
+ break;
+ }
+
+ iface->freq = freq_params->freq;
+ iface->conf->channel = freq_params->channel;
+ iface->conf->secondary_channel = freq_params->sec_channel_offset;
+ iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx;
+ iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx;
+ iface->conf->vht_oper_chwidth = vht_bw;
+ iface->conf->ieee80211n = freq_params->ht_enabled;
+ iface->conf->ieee80211ac = freq_params->vht_enabled;
+
+ /*
+ * cs_params must not be cleared earlier because the freq_params
+ * argument may actually point to one of these.
+ */
+ for (i = 0; i < iface->num_bss; i++)
+ hostapd_cleanup_cs_params(iface->bss[i]);
+
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+}
+
#endif /* NEED_AP_MLME */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index bd85c54..3c8727b 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -210,6 +210,14 @@
size_t psk_len);
void *new_psk_cb_ctx;
+ /* channel switch parameters */
+ struct hostapd_freq_params cs_freq_params;
+ u8 cs_count;
+ int cs_block_tx;
+ unsigned int cs_c_off_beacon;
+ unsigned int cs_c_off_proberesp;
+ int csa_in_progress;
+
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
@@ -343,14 +351,6 @@
/* lowest observed noise floor in dBm */
s8 lowest_nf;
- /* channel switch parameters */
- struct hostapd_freq_params cs_freq_params;
- u8 cs_count;
- int cs_block_tx;
- unsigned int cs_c_off_beacon;
- unsigned int cs_c_off_proberesp;
- int csa_in_progress;
-
unsigned int dfs_cac_ms;
struct os_reltime dfs_cac_start;
@@ -397,6 +397,9 @@
const char * hostapd_state_text(enum hostapd_iface_state s);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
+void
+hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ const struct hostapd_freq_params *freq_params);
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
/* utils.c */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 33f53af..352c163 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -3316,7 +3316,8 @@
* the driver does not support radar detection and another virtual
* interfaces caused the operating channel to change. Other similar
* resource conflicts could also trigger this for station mode
- * interfaces.
+ * interfaces. This event can be propagated when channel switching
+ * fails.
*/
EVENT_INTERFACE_UNAVAILABLE,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c154ec2..4d5da94 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -348,6 +348,8 @@
void *timeout_ctx);
static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
enum nl80211_iftype nlmode);
+static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss, int freq);
+
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
const u8 *set_addr, int first);
@@ -414,6 +416,7 @@
static int wpa_driver_nl80211_authenticate_retry(
struct wpa_driver_nl80211_data *drv);
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
static int i802_set_iface_flags(struct i802_bss *bss, int up);
@@ -1677,7 +1680,7 @@
bss->freq = data.ch_switch.freq;
- wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
+ wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
}
@@ -8594,8 +8597,7 @@
wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
- if (wpa_driver_nl80211_set_mode(drv->first_bss,
- NL80211_IFTYPE_ADHOC)) {
+ if (wpa_driver_nl80211_set_mode_ibss(drv->first_bss, params->freq)) {
wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
"IBSS mode");
return -1;
@@ -9035,26 +9037,29 @@
}
-static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
- enum nl80211_iftype nlmode)
+static int wpa_driver_nl80211_set_mode_impl(
+ struct i802_bss *bss,
+ enum nl80211_iftype nlmode,
+ struct hostapd_freq_params *desired_freq_params)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
int i;
int was_ap = is_ap_interface(drv->nlmode);
int res;
+ int mode_switch_res;
- res = nl80211_set_mode(drv, drv->ifindex, nlmode);
- if (res && nlmode == nl80211_get_ifmode(bss))
- res = 0;
+ mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+ if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
+ mode_switch_res = 0;
- if (res == 0) {
+ if (mode_switch_res == 0) {
drv->nlmode = nlmode;
ret = 0;
goto done;
}
- if (res == -ENODEV)
+ if (mode_switch_res == -ENODEV)
return -1;
if (nlmode == drv->nlmode) {
@@ -9074,21 +9079,35 @@
res = i802_set_iface_flags(bss, 0);
if (res == -EACCES || res == -ENODEV)
break;
- if (res == 0) {
- /* Try to set the mode again while the interface is
- * down */
- ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
- if (ret == -EACCES)
- break;
- res = i802_set_iface_flags(bss, 1);
- if (res && !ret)
- ret = -1;
- else if (ret != -EBUSY)
- break;
- } else
+ if (res != 0) {
wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
"interface down");
- os_sleep(0, 100000);
+ os_sleep(0, 100000);
+ continue;
+ }
+
+ /*
+ * Setting the mode will fail for some drivers if the phy is
+ * on a frequency that the mode is disallowed in.
+ */
+ if (desired_freq_params) {
+ res = i802_set_freq(bss, desired_freq_params);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to set frequency on interface");
+ }
+ }
+
+ /* Try to set the mode again while the interface is down */
+ mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+ if (mode_switch_res == -EBUSY) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Delaying mode set while interface going down");
+ os_sleep(0, 100000);
+ continue;
+ }
+ ret = mode_switch_res;
+ break;
}
if (!ret) {
@@ -9098,6 +9117,14 @@
drv->ignore_if_down_event = 1;
}
+ /* Bring the interface back up */
+ res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
+ if (res != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to set interface up after switching mode");
+ ret = -1;
+ }
+
done:
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
@@ -9160,6 +9187,23 @@
}
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+ enum nl80211_iftype nlmode)
+{
+ return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
+}
+
+
+static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss, int freq)
+{
+ struct hostapd_freq_params freq_params;
+ os_memset(&freq_params, 0, sizeof(freq_params));
+ freq_params.freq = freq;
+ return wpa_driver_nl80211_set_mode_impl(bss, NL80211_IFTYPE_ADHOC,
+ &freq_params);
+}
+
+
static int wpa_driver_nl80211_get_capa(void *priv,
struct wpa_driver_capa *capa)
{
@@ -12074,7 +12118,7 @@
return -ENOMEM;
nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count);
ret = nl80211_put_freq_params(msg, &settings->freq_params);
if (ret)
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index d0191e7..48f3aa6 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -4494,6 +4494,19 @@
}
+void p2p_loop_on_known_peers(struct p2p_data *p2p,
+ void (*peer_callback)(struct p2p_peer_info *peer,
+ void *user_data),
+ void *user_data)
+{
+ struct p2p_device *dev, *n;
+
+ dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) {
+ peer_callback(&dev->info, user_data);
+ }
+}
+
+
#ifdef CONFIG_WPS_NFC
static struct wpabuf * p2p_build_nfc_handover(struct p2p_data *p2p,
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 5938aa7..16500a8 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1788,7 +1788,7 @@
* @group: P2P group context from p2p_group_init()
* @next: iteration pointer, must be a pointer to a void * that is set to %NULL
* on the first call and not modified later
- * Returns: A P2P Interface Address for each call and %NULL for no more members
+ * Returns: A P2P Device Address for each call and %NULL for no more members
*/
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
@@ -1810,6 +1810,26 @@
int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr);
/**
+ * p2p_group_get_config - Get the group configuration
+ * @group: P2P group context from p2p_group_init()
+ * Returns: The group configuration pointer
+ */
+const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group);
+
+/**
+ * p2p_loop_on_all_groups - Run the given callback on all groups
+ * @p2p: P2P module context from p2p_init()
+ * @group_callback: The callback function pointer
+ * @user_data: Some user data pointer which can be %NULL
+ *
+ * The group_callback function can stop the iteration by returning 0.
+ */
+void p2p_loop_on_all_groups(struct p2p_data *p2p,
+ int (*group_callback)(struct p2p_group *group,
+ void *user_data),
+ void *user_data);
+
+/**
* p2p_get_peer_found - Get P2P peer info structure of a found peer
* @p2p: P2P module context from p2p_init()
* @addr: P2P Device Address of the peer or %NULL to indicate the first peer
@@ -1970,4 +1990,9 @@
int p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len);
+void p2p_loop_on_known_peers(struct p2p_data *p2p,
+ void (*peer_callback)(struct p2p_peer_info *peer,
+ void *user_data),
+ void *user_data);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 395ca08..aa075bd 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -973,7 +973,7 @@
if (!iter)
return NULL;
- return iter->addr;
+ return iter->dev_addr;
}
@@ -1013,3 +1013,23 @@
{
return group->cfg->freq;
}
+
+
+const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group)
+{
+ return group->cfg;
+}
+
+
+void p2p_loop_on_all_groups(struct p2p_data *p2p,
+ int (*group_callback)(struct p2p_group *group,
+ void *user_data),
+ void *user_data)
+{
+ unsigned int i;
+
+ for (i = 0; i < p2p->num_groups; i++) {
+ if (!group_callback(p2p->groups[i], user_data))
+ break;
+ }
+}
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 652e52c..cda6957 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -631,7 +631,33 @@
}
-static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+static void wpa_tdls_peer_remove_from_list(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer)
+{
+ struct wpa_tdls_peer *cur, *prev;
+
+ cur = sm->tdls;
+ prev = NULL;
+ while (cur && cur != peer) {
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur != peer) {
+ wpa_printf(MSG_ERROR, "TDLS: Could not find peer " MACSTR
+ " to remove it from the list",
+ MAC2STR(peer->addr));
+ return;
+ }
+
+ if (prev)
+ prev->next = peer->next;
+ else
+ sm->tdls = peer->next;
+}
+
+
+static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR,
MAC2STR(peer->addr));
@@ -663,6 +689,14 @@
}
+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+ wpa_tdls_peer_clear(sm, peer);
+ wpa_tdls_peer_remove_from_list(sm, peer);
+ os_free(peer);
+}
+
+
static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
struct wpa_tdls_lnkid *lnkid)
{
@@ -1597,6 +1631,23 @@
}
+static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+ int add)
+{
+ return wpa_sm_tdls_peer_addset(sm, peer->addr, add, peer->aid,
+ peer->capability,
+ peer->supp_rates, peer->supp_rates_len,
+ peer->ht_capabilities,
+ peer->vht_capabilities,
+ peer->qos_info, peer->ext_capab,
+ peer->ext_capab_len,
+ peer->supp_channels,
+ peer->supp_channels_len,
+ peer->supp_oper_classes,
+ peer->supp_oper_classes_len);
+}
+
+
static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -1644,16 +1695,16 @@
wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
"direct link is enabled - tear down the "
"old link first");
- wpa_tdls_disable_peer_link(sm, peer);
- }
-
- /*
- * An entry is already present, so check if we already sent a
- * TDLS Setup Request. If so, compare MAC addresses and let the
- * STA with the lower MAC address continue as the initiator.
- * The other negotiation is terminated.
- */
- if (peer->initiator) {
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ wpa_tdls_peer_clear(sm, peer);
+ } else if (peer->initiator) {
+ /*
+ * An entry is already present, so check if we already
+ * sent a TDLS Setup Request. If so, compare MAC
+ * addresses and let the STA with the lower MAC address
+ * continue as the initiator. The other negotiation is
+ * terminated.
+ */
if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
wpa_printf(MSG_DEBUG, "TDLS: Discard request "
"from peer with higher address "
@@ -1665,7 +1716,9 @@
MACSTR " (terminate previously "
"initiated negotiation",
MAC2STR(src_addr));
- wpa_tdls_disable_peer_link(sm, peer);
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+ peer->addr);
+ wpa_tdls_peer_clear(sm, peer);
}
}
}
@@ -1909,16 +1962,15 @@
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
skip_rsn_check:
- /* add the peer to the driver as a "setup in progress" peer */
- if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
- NULL, 0, NULL, 0, NULL, 0, NULL, 0))
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 1) < 0)
goto error;
peer->tpk_in_progress = 1;
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
- wpa_tdls_disable_peer_link(sm, peer);
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
goto error;
}
@@ -1957,20 +2009,6 @@
#endif /* CONFIG_TDLS_TESTING */
}
- /* add supported rates, capabilities, and qos_info to the TDLS peer */
- if (wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->aid,
- peer->capability,
- peer->supp_rates, peer->supp_rates_len,
- peer->ht_capabilities,
- peer->vht_capabilities,
- peer->qos_info, peer->ext_capab,
- peer->ext_capab_len,
- peer->supp_channels,
- peer->supp_channels_len,
- peer->supp_oper_classes,
- peer->supp_oper_classes_len) < 0)
- return -1;
-
if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) {
wpa_printf(MSG_INFO, "TDLS: Could not configure key to the "
"driver");
@@ -2224,12 +2262,14 @@
skip_rsn:
peer->dtoken = dtoken;
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 0) < 0)
+ goto error;
+
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
"TPK Handshake Message 3");
- if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0) {
- wpa_tdls_disable_peer_link(sm, peer);
- return -1;
- }
+ if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0)
+ goto error;
if (!peer->tpk_success) {
/*
@@ -2391,6 +2431,10 @@
}
skip_rsn:
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 0) < 0)
+ goto error;
+
if (!peer->tpk_success) {
/*
* Enable Link only when tpk_success is 0, signifying that this
@@ -2400,14 +2444,12 @@
ret = wpa_tdls_enable_link(sm, peer);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
- wpa_tdls_do_teardown(
- sm, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ goto error;
}
}
return ret;
error:
- wpa_tdls_disable_peer_link(sm, peer);
+ wpa_tdls_do_teardown(sm, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
return -1;
}
@@ -2470,8 +2512,11 @@
peer->initiator = 1;
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
- NULL, 0, NULL, 0, NULL, 0);
+ if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
+ NULL, 0, NULL, 0, NULL, 0, NULL, 0)) {
+ wpa_tdls_disable_peer_link(sm, peer);
+ return -1;
+ }
peer->tpk_in_progress = 1;
@@ -2621,13 +2666,14 @@
void wpa_tdls_teardown_peers(struct wpa_sm *sm)
{
- struct wpa_tdls_peer *peer;
+ struct wpa_tdls_peer *peer, *tmp;
peer = sm->tdls;
wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
while (peer) {
+ tmp = peer->next;
wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR,
MAC2STR(peer->addr));
if (sm->tdls_external_setup)
@@ -2636,7 +2682,7 @@
else
wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
- peer = peer->next;
+ peer = tmp;
}
}
@@ -2646,7 +2692,6 @@
struct wpa_tdls_peer *peer, *tmp;
peer = sm->tdls;
- sm->tdls = NULL;
while (peer) {
int res;
@@ -2655,7 +2700,6 @@
wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)",
MAC2STR(peer->addr), res);
wpa_tdls_peer_free(sm, peer);
- os_free(peer);
peer = tmp;
}
}