diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 2f6932b88..17c024ce0 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -659,3 +659,13 @@ struct wpa_scan_results * hostapd_driver_get_scan_results( return hapd->driver->get_scan_results2(hapd->drv_priv); return NULL; } + + +int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start, + int duration) +{ + if (hapd->driver && hapd->driver->set_noa) + return hapd->driver->set_noa(hapd->drv_priv, count, start, + duration); + return -1; +} diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 9b75d096a..d8f9ddcb8 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -63,5 +63,7 @@ int hostapd_driver_scan(struct hostapd_data *hapd, struct wpa_driver_scan_params *params); struct wpa_scan_results * hostapd_driver_get_scan_results( struct hostapd_data *hapd); +int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start, + int duration); #endif /* AP_DRV_OPS */ diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 2d50a5149..cd9e87b88 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -35,6 +35,7 @@ #include "wpa_auth_glue.h" #include "ap_drv_ops.h" #include "ap_config.h" +#include "p2p_hostapd.h" static int hostapd_flush_old_stations(struct hostapd_data *hapd); @@ -877,6 +878,15 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, if (hapd->conf->ieee802_11f) iapp_new_station(hapd->iapp, sta); +#ifdef CONFIG_P2P + if (sta->p2p_ie == NULL && !sta->no_p2p_set) { + sta->no_p2p_set = 1; + hapd->num_sta_no_p2p++; + if (hapd->num_sta_no_p2p == 1) + hostapd_p2p_non_p2p_sta_connected(hapd); + } +#endif /* CONFIG_P2P */ + /* Start accounting here, if IEEE 802.1X and WPA are not used. * IEEE 802.1X/WPA code will start accounting after the station has * been authorized. */ diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 3efcdfad6..021d2e884 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -190,6 +190,14 @@ struct hostapd_data { struct p2p_group *p2p_group; struct wpabuf *p2p_beacon_ie; struct wpabuf *p2p_probe_resp_ie; + + /* Number of non-P2P association stations */ + int num_sta_no_p2p; + + /* Periodic NoA (used only when no non-P2P clients in the group) */ + int noa_enabled; + int noa_start; + int noa_duration; #endif /* CONFIG_P2P */ }; diff --git a/src/ap/p2p_hostapd.c b/src/ap/p2p_hostapd.c index 7f998300a..ffe16bbf0 100644 --- a/src/ap/p2p_hostapd.c +++ b/src/ap/p2p_hostapd.c @@ -1,6 +1,6 @@ /* * hostapd / P2P integration - * Copyright (c) 2009, Atheros Communications + * Copyright (c) 2009-2010, Atheros Communications * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,6 +16,8 @@ #include "utils/common.h" #include "p2p/p2p.h" +#include "hostapd.h" +#include "ap_drv_ops.h" #include "sta_info.h" #include "p2p_hostapd.h" @@ -28,3 +30,61 @@ int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, return p2p_ie_text(sta->p2p_ie, buf, buf + buflen); } + + +int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start, + int duration) +{ + wpa_printf(MSG_DEBUG, "P2P: Set NoA parameters: count=%u start=%d " + "duration=%d", count, start, duration); + + if (count == 0) { + hapd->noa_enabled = 0; + hapd->noa_start = 0; + hapd->noa_duration = 0; + } + + if (count != 255) { + wpa_printf(MSG_DEBUG, "P2P: Non-periodic NoA - set " + "NoA parameters"); + return hostapd_driver_set_noa(hapd, count, start, duration); + } + + hapd->noa_enabled = 1; + hapd->noa_start = start; + hapd->noa_duration = duration; + + if (hapd->num_sta_no_p2p == 0) { + wpa_printf(MSG_DEBUG, "P2P: No legacy STAs connected - update " + "periodic NoA parameters"); + return hostapd_driver_set_noa(hapd, count, start, duration); + } + + wpa_printf(MSG_DEBUG, "P2P: Legacy STA(s) connected - do not enable " + "periodic NoA"); + + return 0; +} + + +void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd) +{ + wpa_printf(MSG_DEBUG, "P2P: First non-P2P device connected"); + + if (hapd->noa_enabled) { + wpa_printf(MSG_DEBUG, "P2P: Disable periodic NoA"); + hostapd_driver_set_noa(hapd, 0, 0, 0); + } +} + + +void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd) +{ + wpa_printf(MSG_DEBUG, "P2P: Last non-P2P device disconnected"); + + if (hapd->noa_enabled) { + wpa_printf(MSG_DEBUG, "P2P: Enable periodic NoA"); + hostapd_driver_set_noa(hapd, 255, hapd->noa_start, + hapd->noa_duration); + } +} diff --git a/src/ap/p2p_hostapd.h b/src/ap/p2p_hostapd.h index 31aed1521..643ad6c66 100644 --- a/src/ap/p2p_hostapd.h +++ b/src/ap/p2p_hostapd.h @@ -1,6 +1,6 @@ /* * hostapd / P2P integration - * Copyright (c) 2009, Atheros Communications + * Copyright (c) 2009-2010, Atheros Communications * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,6 +19,11 @@ int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, char *buf, size_t buflen); +int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start, + int duration); +void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd); +void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd); + #else /* CONFIG_P2P */ diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 8cd6c3f1f..80cdb625a 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -31,6 +31,7 @@ #include "beacon.h" #include "ap_mlme.h" #include "vlan_init.h" +#include "p2p_hostapd.h" #include "sta_info.h" static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, @@ -174,6 +175,15 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) hapd->iface->num_sta_ht_20mhz--; } +#ifdef CONFIG_P2P + if (sta->no_p2p_set) { + sta->no_p2p_set = 0; + hapd->num_sta_no_p2p--; + if (hapd->num_sta_no_p2p == 0) + hostapd_p2p_non_p2p_sta_disconnected(hapd); + } +#endif /* CONFIG_P2P */ + #if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N) if (hostapd_ht_operation_update(hapd->iface) > 0) set_beacon++; diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index e65ddef0e..51bd9d27a 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -55,6 +55,7 @@ struct sta_info { unsigned int no_ht_gf_set:1; unsigned int no_ht_set:1; unsigned int ht_20mhz_set:1; + unsigned int no_p2p_set:1; u16 auth_alg; u8 previous_ap[6]; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index e82d31d17..835575747 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -2438,7 +2438,7 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) return -1; wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d " "start=%d duration=%d", count, start, duration); - return wpa_drv_set_noa(wpa_s, count, start, duration); + return wpas_p2p_set_noa(wpa_s, count, start, duration); } if (os_strcmp(cmd, "ps") == 0) diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 0868fa8fa..2e404e992 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -514,14 +514,6 @@ static inline int wpa_drv_get_noa(struct wpa_supplicant *wpa_s, return wpa_s->driver->get_noa(wpa_s->drv_priv, buf, buf_len); } -static inline int wpa_drv_set_noa(struct wpa_supplicant *wpa_s, u8 count, - int start, int duration) -{ - if (!wpa_s->driver->set_noa) - return -1; - return wpa_s->driver->set_noa(wpa_s->drv_priv, count, start, duration); -} - static inline int wpa_drv_set_p2p_powersave(struct wpa_supplicant *wpa_s, int legacy_ps, int opp_ps, int ctwindow) diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 60a3c668f..b25765432 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -22,6 +22,7 @@ #include "wps/wps_i.h" #include "p2p/p2p.h" #include "ap/hostapd.h" +#include "ap/p2p_hostapd.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "ap.h" @@ -3296,3 +3297,13 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s) 0); } } + + +int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start, + int duration) +{ + if (!wpa_s->ap_iface) + return -1; + return hostapd_p2p_set_noa(wpa_s->ap_iface->bss[0], count, start, + duration); +} diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 075cda82b..e1578fca9 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -106,5 +106,7 @@ void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, u16 reason_code, const u8 *ie, size_t ie_len); void wpas_p2p_update_config(struct wpa_supplicant *wpa_s); +int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start, + int duration); #endif /* P2P_SUPPLICANT_H */