P2P: Add a command for removing a client from all groups
The new control interface command P2P_REMOVE_CLIENT <P2P Device Address|iface=Address> can now be used to remove the specified client from all groups (ongoing and persistent) in which the local device is a GO. This will remove any per-client PSK entries and deauthenticate the device. Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
01a57fe420
commit
f2c566027e
6 changed files with 176 additions and 6 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* hostapd / Station table
|
* hostapd / Station table
|
||||||
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* See README for more details.
|
||||||
|
@ -70,6 +70,30 @@ struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_P2P
|
||||||
|
struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr)
|
||||||
|
{
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
|
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||||
|
const u8 *p2p_dev_addr;
|
||||||
|
|
||||||
|
if (sta->p2p_ie == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
|
||||||
|
if (p2p_dev_addr == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0)
|
||||||
|
return sta;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
|
|
||||||
static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
|
static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
{
|
{
|
||||||
struct sta_info *tmp;
|
struct sta_info *tmp;
|
||||||
|
|
|
@ -156,6 +156,7 @@ int ap_for_each_sta(struct hostapd_data *hapd,
|
||||||
void *ctx),
|
void *ctx),
|
||||||
void *ctx);
|
void *ctx);
|
||||||
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
|
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
|
||||||
|
struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr);
|
||||||
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
|
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
|
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
void hostapd_free_stas(struct hostapd_data *hapd);
|
void hostapd_free_stas(struct hostapd_data *hapd);
|
||||||
|
|
|
@ -4629,6 +4629,25 @@ static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
|
||||||
return wpas_p2p_ext_listen(wpa_s, period, interval);
|
return wpas_p2p_ext_listen(wpa_s, period, interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
|
||||||
|
{
|
||||||
|
const char *pos;
|
||||||
|
u8 peer[ETH_ALEN];
|
||||||
|
int iface_addr = 0;
|
||||||
|
|
||||||
|
pos = cmd;
|
||||||
|
if (os_strncmp(pos, "iface=", 6) == 0) {
|
||||||
|
iface_addr = 1;
|
||||||
|
pos += 6;
|
||||||
|
}
|
||||||
|
if (hwaddr_aton(pos, peer))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
wpas_p2p_remove_client(wpa_s, peer, iface_addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
|
|
||||||
|
@ -5450,6 +5469,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
||||||
} else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
|
} else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
|
||||||
if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
|
if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
|
} else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
|
||||||
|
if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
|
||||||
|
reply_len = -1;
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
#ifdef CONFIG_WIFI_DISPLAY
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
|
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
|
||||||
|
@ -5936,6 +5958,7 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
|
||||||
"P2P_UNAUTHORIZE ",
|
"P2P_UNAUTHORIZE ",
|
||||||
"P2P_PRESENCE_REQ ",
|
"P2P_PRESENCE_REQ ",
|
||||||
"P2P_EXT_LISTEN ",
|
"P2P_EXT_LISTEN ",
|
||||||
|
"P2P_REMOVE_CLIENT ",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include "p2p/p2p.h"
|
#include "p2p/p2p.h"
|
||||||
#include "ap/hostapd.h"
|
#include "ap/hostapd.h"
|
||||||
#include "ap/ap_config.h"
|
#include "ap/ap_config.h"
|
||||||
|
#include "ap/sta_info.h"
|
||||||
|
#include "ap/ap_drv_ops.h"
|
||||||
#include "ap/p2p_hostapd.h"
|
#include "ap/p2p_hostapd.h"
|
||||||
#include "eapol_supp/eapol_supp_sm.h"
|
#include "eapol_supp/eapol_supp_sm.h"
|
||||||
#include "rsn_supp/wpa.h"
|
#include "rsn_supp/wpa.h"
|
||||||
|
@ -2700,7 +2702,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
|
||||||
|
|
||||||
static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
|
static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
|
||||||
struct wpa_ssid *ssid,
|
struct wpa_ssid *ssid,
|
||||||
const u8 *peer)
|
const u8 *peer, int inv)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
@ -2725,8 +2727,9 @@ static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Remove peer " MACSTR " from persistent "
|
wpa_printf(MSG_DEBUG, "P2P: Remove peer " MACSTR " from persistent "
|
||||||
"group %d client list due to invitation result",
|
"group %d client list%s",
|
||||||
MAC2STR(peer), ssid->id);
|
MAC2STR(peer), ssid->id,
|
||||||
|
inv ? " due to invitation result" : "");
|
||||||
os_memmove(ssid->p2p_client_list + i * ETH_ALEN,
|
os_memmove(ssid->p2p_client_list + i * ETH_ALEN,
|
||||||
ssid->p2p_client_list + (i + 1) * ETH_ALEN,
|
ssid->p2p_client_list + (i + 1) * ETH_ALEN,
|
||||||
(ssid->num_p2p_clients - i - 1) * ETH_ALEN);
|
(ssid->num_p2p_clients - i - 1) * ETH_ALEN);
|
||||||
|
@ -2753,7 +2756,7 @@ static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s,
|
||||||
return; /* Not operating as a GO in persistent group */
|
return; /* Not operating as a GO in persistent group */
|
||||||
ssid = wpas_p2p_get_persistent(wpa_s->parent, peer,
|
ssid = wpas_p2p_get_persistent(wpa_s->parent, peer,
|
||||||
ssid->ssid, ssid->ssid_len);
|
ssid->ssid, ssid->ssid_len);
|
||||||
wpas_remove_persistent_peer(wpa_s, ssid, peer);
|
wpas_remove_persistent_peer(wpa_s, ssid, peer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2792,7 +2795,7 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
|
||||||
if (status == P2P_SC_FAIL_UNKNOWN_GROUP) {
|
if (status == P2P_SC_FAIL_UNKNOWN_GROUP) {
|
||||||
ssid = wpa_config_get_network(
|
ssid = wpa_config_get_network(
|
||||||
wpa_s->conf, wpa_s->pending_invite_ssid_id);
|
wpa_s->conf, wpa_s->pending_invite_ssid_id);
|
||||||
wpas_remove_persistent_peer(wpa_s, ssid, peer);
|
wpas_remove_persistent_peer(wpa_s, ssid, peer, 1);
|
||||||
}
|
}
|
||||||
wpas_p2p_remove_pending_group_interface(wpa_s);
|
wpas_p2p_remove_pending_group_interface(wpa_s);
|
||||||
return;
|
return;
|
||||||
|
@ -6116,3 +6119,110 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
|
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
|
||||||
#endif /* CONFIG_NO_CONFIG_WRITE */
|
#endif /* CONFIG_NO_CONFIG_WRITE */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_p2p_remove_psk(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpa_ssid *s, const u8 *addr,
|
||||||
|
int iface_addr)
|
||||||
|
{
|
||||||
|
struct psk_list_entry *psk, *tmp;
|
||||||
|
int changed = 0;
|
||||||
|
|
||||||
|
dl_list_for_each_safe(psk, tmp, &s->psk_list, struct psk_list_entry,
|
||||||
|
list) {
|
||||||
|
if ((iface_addr && !psk->p2p &&
|
||||||
|
os_memcmp(addr, psk->addr, ETH_ALEN) == 0) ||
|
||||||
|
(!iface_addr && psk->p2p &&
|
||||||
|
os_memcmp(addr, psk->addr, ETH_ALEN) == 0)) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||||
|
"P2P: Remove persistent group PSK list entry for "
|
||||||
|
MACSTR " p2p=%u",
|
||||||
|
MAC2STR(psk->addr), psk->p2p);
|
||||||
|
dl_list_del(&psk->list);
|
||||||
|
os_free(psk);
|
||||||
|
changed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef CONFIG_NO_CONFIG_WRITE
|
||||||
|
if (changed && wpa_s->conf->update_config &&
|
||||||
|
wpa_config_write(wpa_s->confname, wpa_s->conf))
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||||
|
"P2P: Failed to update configuration");
|
||||||
|
#endif /* CONFIG_NO_CONFIG_WRITE */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_p2p_remove_client_go(struct wpa_supplicant *wpa_s,
|
||||||
|
const u8 *peer, int iface_addr)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd;
|
||||||
|
struct hostapd_wpa_psk *psk, *prev, *rem;
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
|
if (wpa_s->ap_iface == NULL || wpa_s->current_ssid == NULL ||
|
||||||
|
wpa_s->current_ssid->mode != WPAS_MODE_P2P_GO)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Remove per-station PSK entry */
|
||||||
|
hapd = wpa_s->ap_iface->bss[0];
|
||||||
|
prev = NULL;
|
||||||
|
psk = hapd->conf->ssid.wpa_psk;
|
||||||
|
while (psk) {
|
||||||
|
if ((iface_addr && os_memcmp(peer, psk->addr, ETH_ALEN) == 0) ||
|
||||||
|
(!iface_addr &&
|
||||||
|
os_memcmp(peer, psk->p2p_dev_addr, ETH_ALEN) == 0)) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove operating group PSK entry for "
|
||||||
|
MACSTR " iface_addr=%d",
|
||||||
|
MAC2STR(peer), iface_addr);
|
||||||
|
if (prev)
|
||||||
|
prev->next = psk->next;
|
||||||
|
else
|
||||||
|
hapd->conf->ssid.wpa_psk = psk->next;
|
||||||
|
rem = psk;
|
||||||
|
psk = psk->next;
|
||||||
|
os_free(rem);
|
||||||
|
} else {
|
||||||
|
prev = psk;
|
||||||
|
psk = psk->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disconnect from group */
|
||||||
|
if (iface_addr)
|
||||||
|
sta = ap_get_sta(hapd, peer);
|
||||||
|
else
|
||||||
|
sta = ap_get_sta_p2p(hapd, peer);
|
||||||
|
if (sta) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disconnect peer " MACSTR
|
||||||
|
" (iface_addr=%d) from group",
|
||||||
|
MAC2STR(peer), iface_addr);
|
||||||
|
hostapd_drv_sta_deauth(hapd, sta->addr,
|
||||||
|
WLAN_REASON_DEAUTH_LEAVING);
|
||||||
|
ap_sta_deauthenticate(hapd, sta, WLAN_REASON_DEAUTH_LEAVING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
|
||||||
|
int iface_addr)
|
||||||
|
{
|
||||||
|
struct wpa_ssid *s;
|
||||||
|
struct wpa_supplicant *w;
|
||||||
|
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove client " MACSTR, MAC2STR(peer));
|
||||||
|
|
||||||
|
/* Remove from any persistent group */
|
||||||
|
for (s = wpa_s->parent->conf->ssid; s; s = s->next) {
|
||||||
|
if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO)
|
||||||
|
continue;
|
||||||
|
if (!iface_addr)
|
||||||
|
wpas_remove_persistent_peer(wpa_s, s, peer, 0);
|
||||||
|
wpas_p2p_remove_psk(wpa_s->parent, s, peer, iface_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove from any operating group */
|
||||||
|
for (w = wpa_s->global->ifaces; w; w = w->next)
|
||||||
|
wpas_p2p_remove_client_go(w, peer, iface_addr);
|
||||||
|
}
|
||||||
|
|
|
@ -155,6 +155,8 @@ unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
|
||||||
void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
|
void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
|
||||||
const u8 *p2p_dev_addr,
|
const u8 *p2p_dev_addr,
|
||||||
const u8 *psk, size_t psk_len);
|
const u8 *psk, size_t psk_len);
|
||||||
|
void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
|
||||||
|
int iface_addr);
|
||||||
|
|
||||||
#ifdef CONFIG_P2P
|
#ifdef CONFIG_P2P
|
||||||
void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s);
|
void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s);
|
||||||
|
|
|
@ -2149,6 +2149,13 @@ static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
|
||||||
return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
|
return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
#ifdef CONFIG_WIFI_DISPLAY
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
@ -2745,6 +2752,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
|
||||||
{ "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
|
{ "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
|
||||||
cli_cmd_flag_none,
|
cli_cmd_flag_none,
|
||||||
"[<period> <interval>] = set extended listen timing" },
|
"[<period> <interval>] = set extended listen timing" },
|
||||||
|
{ "p2p_remove_client", wpa_cli_cmd_p2p_remove_client,
|
||||||
|
wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
|
||||||
|
"<address|iface=address> = remove a peer from all groups" },
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
#ifdef CONFIG_WIFI_DISPLAY
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
{ "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
|
{ "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
|
||||||
|
|
Loading…
Reference in a new issue