diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ap/beacon.c | 20 | ||||
| -rw-r--r-- | src/ap/dfs.c | 23 | ||||
| -rw-r--r-- | src/ap/drv_callbacks.c | 22 | ||||
| -rw-r--r-- | src/ap/hostapd.c | 105 | ||||
| -rw-r--r-- | src/ap/hostapd.h | 19 | ||||
| -rw-r--r-- | src/drivers/driver.h | 3 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.c | 92 | ||||
| -rw-r--r-- | src/p2p/p2p.c | 13 | ||||
| -rw-r--r-- | src/p2p/p2p.h | 27 | ||||
| -rw-r--r-- | src/p2p/p2p_group.c | 22 | ||||
| -rw-r--r-- | src/rsn_supp/tdls.c | 132 |
11 files changed, 358 insertions, 120 deletions
diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 73dffe2c..b3b61498 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -265,18 +265,18 @@ static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) { 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 @@ static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid) { 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 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, 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 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, 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 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) 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 c30f6d6a..a11b2cf8 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -756,6 +756,16 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) } +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 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) 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 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) 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 fb095efb..93804de0 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -489,9 +489,10 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, 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 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd, #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 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, 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 4e09fa3a..55b7ced8 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -2175,13 +2175,12 @@ static void free_beacon_data(struct beacon_data *beacon) } -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 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, 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_change_config_freq(struct hostapd_data *hapd, } -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 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface, 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 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface, 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 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface, 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 @@ int hostapd_switch_channel(struct hostapd_data *hapd, 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 @@ int hostapd_switch_channel(struct hostapd_data *hapd, 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 bd85c54a..3c8727b1 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -210,6 +210,14 @@ struct hostapd_data { 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 @@ struct hostapd_iface { /* 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 @@ void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s); 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 33f53af3..352c163b 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -3316,7 +3316,8 @@ enum wpa_event_type { * 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 c154ec21..4d5da949 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -348,6 +348,8 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, 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 nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv); 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 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, 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 @@ static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv, 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 @@ nla_put_failure: } -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 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, 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 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, 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 dfs_info_handler(struct nl_msg *msg, void *arg) } +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 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) 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 d0191e74..48f3aa65 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -4494,6 +4494,19 @@ void p2p_err(struct p2p_data *p2p, const char *fmt, ...) } +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 5938aa71..16500a80 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1788,7 +1788,7 @@ unsigned int p2p_get_group_num_members(struct p2p_group *group); * @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 @@ const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr); 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 @@ void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id, 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 395ca089..aa075bdb 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -973,7 +973,7 @@ const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next) if (!iter) return NULL; - return iter->addr; + return iter->dev_addr; } @@ -1013,3 +1013,23 @@ int p2p_group_get_freq(struct p2p_group *group) { 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 652e52c6..cda69574 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -631,7 +631,33 @@ static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx) } -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) } +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 copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde, } +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 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, 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 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, 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 @@ skip_rsn: 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 @@ static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) #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 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, 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 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, } 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 @@ skip_rsn: 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 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) 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 @@ int wpa_tdls_init(struct wpa_sm *sm) 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 @@ void wpa_tdls_teardown_peers(struct wpa_sm *sm) else wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); - peer = peer->next; + peer = tmp; } } @@ -2646,7 +2692,6 @@ static void wpa_tdls_remove_peers(struct wpa_sm *sm) struct wpa_tdls_peer *peer, *tmp; peer = sm->tdls; - sm->tdls = NULL; while (peer) { int res; @@ -2655,7 +2700,6 @@ static void wpa_tdls_remove_peers(struct wpa_sm *sm) 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; } } |
