From b1f625e0d81b76bb2380d0b47b95f5ad61123ba5 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 17 Jul 2011 20:22:11 +0300 Subject: [PATCH] nl80211: Consider P2P when changing vif type Commit 9f51b11395646efeb5d6a75d2cabc0bf7626496f added support for P2P interfaces when adding a new interface. However, it didn't handle the case in which the same interface is being used and its type is being changed. Add support for this case. Consequently, when doing "ap_scan_as_station" we now need to save the actual AP interface type (AP/P2P GO) in order to restore it properly. For that, change ap_scan_as_station type from int to nl80211_iftype, and set it to NL80211_IFTYPE_UNSPECIFED when not used. Signed-off-by: Eliad Peller --- src/drivers/driver_nl80211.c | 114 +++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 52 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 6ba01d465..ae5d8afd4 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -153,8 +153,8 @@ struct wpa_driver_nl80211_data { int associated; u8 ssid[32]; size_t ssid_len; - int nlmode; - int ap_scan_as_station; + enum nl80211_iftype nlmode; + enum nl80211_iftype ap_scan_as_station; unsigned int assoc_freq; int monitor_sock; @@ -189,7 +189,8 @@ struct wpa_driver_nl80211_data { static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx); -static int wpa_driver_nl80211_set_mode(void *priv, int mode); +static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, + enum nl80211_iftype nlmode); static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv); static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, @@ -223,6 +224,20 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv); +static int is_ap_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_AP || + nlmode == NL80211_IFTYPE_P2P_GO); +} + + +static int is_sta_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_STATION || + nlmode == NL80211_IFTYPE_P2P_CLIENT); +} + + struct nl80211_bss_info_arg { struct wpa_driver_nl80211_data *drv; struct wpa_scan_results *res; @@ -1447,12 +1462,12 @@ static int process_event(struct nl_msg *msg, void *arg) } } - if (drv->ap_scan_as_station && + if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS || gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) { wpa_driver_nl80211_set_mode(&drv->first_bss, - IEEE80211_MODE_AP); - drv->ap_scan_as_station = 0; + drv->ap_scan_as_station); + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } switch (gnlh->cmd) { @@ -1966,6 +1981,7 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, drv->monitor_ifidx = -1; drv->monitor_sock = -1; drv->ioctl_sock = -1; + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; if (wpa_driver_nl80211_init_nl(drv)) { os_free(drv); @@ -2140,7 +2156,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) */ if ((drv->global == NULL || drv->ifindex != drv->global->if_add_ifindex) && - wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) { + wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) { wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to " "use managed mode"); } @@ -2236,7 +2252,7 @@ static void wpa_driver_nl80211_deinit(void *priv) nl80211_remove_monitor_interface(drv); - if (drv->nlmode == NL80211_IFTYPE_AP) + if (is_ap_interface(drv->nlmode)) wpa_driver_nl80211_del_beacon(drv); #ifdef HOSTAPD @@ -2267,7 +2283,7 @@ static void wpa_driver_nl80211_deinit(void *priv) eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0); - wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA); + wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION); if (drv->ioctl_sock >= 0) close(drv->ioctl_sock); @@ -2300,10 +2316,10 @@ static void wpa_driver_nl80211_deinit(void *priv) static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_nl80211_data *drv = eloop_ctx; - if (drv->ap_scan_as_station) { + if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) { wpa_driver_nl80211_set_mode(&drv->first_bss, - IEEE80211_MODE_AP); - drv->ap_scan_as_station = 0; + drv->ap_scan_as_station); + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); @@ -2377,23 +2393,22 @@ static int wpa_driver_nl80211_scan(void *priv, wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d " "(%s)", ret, strerror(-ret)); #ifdef HOSTAPD - if (drv->nlmode == NL80211_IFTYPE_AP) { + if (is_ap_interface(drv->nlmode)) { /* * mac80211 does not allow scan requests in AP mode, so * try to do this in station mode. */ - if (wpa_driver_nl80211_set_mode(bss, - IEEE80211_MODE_INFRA)) + if (wpa_driver_nl80211_set_mode( + bss, NL80211_IFTYPE_STATION)) goto nla_put_failure; if (wpa_driver_nl80211_scan(drv, params)) { - wpa_driver_nl80211_set_mode(bss, - IEEE80211_MODE_AP); + wpa_driver_nl80211_set_mode(bss, drv->nlmode); goto nla_put_failure; } /* Restore AP mode when processing scan results */ - drv->ap_scan_as_station = 1; + drv->ap_scan_as_station = drv->nlmode; ret = 0; } else goto nla_put_failure; @@ -2660,7 +2675,7 @@ static void wpa_driver_nl80211_check_bss_status( "indicates BSS status with " MACSTR " as authenticated", MAC2STR(r->bssid)); - if (drv->nlmode == NL80211_IFTYPE_STATION && + if (is_sta_interface(drv->nlmode) && os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 && os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) != 0) { @@ -2678,13 +2693,13 @@ static void wpa_driver_nl80211_check_bss_status( "indicate BSS status with " MACSTR " as associated", MAC2STR(r->bssid)); - if (drv->nlmode == NL80211_IFTYPE_STATION && + if (is_sta_interface(drv->nlmode) && !drv->associated) { wpa_printf(MSG_DEBUG, "nl80211: Local state " "(not associated) does not match " "with BSS state"); clear_state_mismatch(drv, r->bssid); - } else if (drv->nlmode == NL80211_IFTYPE_STATION && + } else if (is_sta_interface(drv->nlmode) && os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "nl80211: Local state " @@ -2892,7 +2907,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, */ if (ret || !set_tx || alg == WPA_ALG_NONE) return ret; - if (drv->nlmode == NL80211_IFTYPE_AP && addr && + if (is_ap_interface(drv->nlmode) && addr && !is_broadcast_ether_addr(addr)) return ret; @@ -3151,7 +3166,7 @@ static int wpa_driver_nl80211_authenticate( os_memset(drv->auth_bssid, 0, ETH_ALEN); /* FIX: IBSS mode */ if (drv->nlmode != NL80211_IFTYPE_STATION && - wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0) + wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION) < 0) return -1; retry: @@ -3745,7 +3760,7 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, mgmt = (struct ieee80211_mgmt *) data; fc = le_to_host16(mgmt->frame_control); - if (drv->nlmode == NL80211_IFTYPE_STATION && + if (is_sta_interface(drv->nlmode) && WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { /* @@ -4587,10 +4602,16 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params) { - if (params->p2p) + enum nl80211_iftype nlmode; + + if (params->p2p) { wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P " "group (GO)"); - if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) || + nlmode = NL80211_IFTYPE_P2P_GO; + } else + nlmode = NL80211_IFTYPE_AP; + + if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) || wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) { nl80211_remove_monitor_interface(drv); return -1; @@ -4641,7 +4662,8 @@ 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, params->mode)) { + if (wpa_driver_nl80211_set_mode(&drv->first_bss, + NL80211_IFTYPE_ADHOC)) { wpa_printf(MSG_INFO, "nl80211: Failed to set interface into " "IBSS mode"); return -1; @@ -4882,7 +4904,10 @@ static int wpa_driver_nl80211_associate( return wpa_driver_nl80211_ibss(drv, params); if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { - if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0) + enum nl80211_iftype nlmode = params->p2p ? + NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; + + if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0) return -1; return wpa_driver_nl80211_connect(drv, params); } @@ -5032,28 +5057,13 @@ nla_put_failure: } -static int wpa_driver_nl80211_set_mode(void *priv, int mode) +static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, + enum nl80211_iftype nlmode) { - struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; int ret = -1; - int nlmode; int i; - switch (mode) { - case 0: - nlmode = NL80211_IFTYPE_STATION; - break; - case 1: - nlmode = NL80211_IFTYPE_ADHOC; - break; - case 2: - nlmode = NL80211_IFTYPE_AP; - break; - default: - return -1; - } - if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) { drv->nlmode = nlmode; ret = 0; @@ -5098,13 +5108,13 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode) } done: - if (!ret && nlmode == NL80211_IFTYPE_AP) { + if (!ret && is_ap_interface(nlmode)) { /* Setup additional AP mode functionality if needed */ if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 && nl80211_create_monitor_interface(drv) && !drv->no_monitor_iface_capab) return -1; - } else if (!ret && nlmode != NL80211_IFTYPE_AP) { + } else if (!ret && !is_ap_interface(nlmode)) { /* Remove additional AP mode functionality */ nl80211_remove_monitor_interface(drv); bss->beacon_set = 0; @@ -5869,7 +5879,7 @@ static void *i802_init(struct hostapd_data *hapd, goto failed; } - if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) { + if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) { wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s " "into AP mode", bss->ifname); goto failed; @@ -6224,7 +6234,7 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq, os_memcpy(hdr->addr2, src, ETH_ALEN); os_memcpy(hdr->addr3, bssid, ETH_ALEN); - if (drv->nlmode == NL80211_IFTYPE_AP) + if (is_ap_interface(drv->nlmode)) ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len); else ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf, @@ -6343,7 +6353,7 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report) struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - if (drv->nlmode != NL80211_IFTYPE_STATION) { + if (!is_sta_interface(drv->nlmode)) { wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only " "allowed in station mode (iftype=%d)", drv->nlmode); @@ -6481,10 +6491,10 @@ static int wpa_driver_nl80211_deinit_ap(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - if (drv->nlmode != NL80211_IFTYPE_AP) + if (!is_ap_interface(drv->nlmode)) return -1; wpa_driver_nl80211_del_beacon(drv); - return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA); + return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION); }