Add ctrl_iface command for triggering a roam to a specific BSS

'wpa_cli roam <bssid>' can now be used to test roaming within an ESS
(e.g., for FT over-the-air). This command will bypass a new scan and
will select the BSS based on the specified BSSID. It is responsibility
of the caller to make sure that the target AP is in the BSS table.
This can be done, e.g., by running a scan before the roam command,
if needed.
This commit is contained in:
Jouni Malinen 2010-04-10 22:56:55 +03:00
parent a7b6c42232
commit 86d4f806da
4 changed files with 72 additions and 3 deletions

View file

@ -1648,6 +1648,46 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
} }
static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
char *addr)
{
u8 bssid[ETH_ALEN];
struct wpa_bss *bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
if (hwaddr_aton(addr, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
"address '%s'", addr);
return -1;
}
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
bss = wpa_bss_get_bssid(wpa_s, bssid);
if (!bss) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
"from BSS table");
return -1;
}
/*
* TODO: Find best network configuration block from configuration to
* allow roaming to other networks
*/
if (!ssid) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
"configuration known for the target AP");
return -1;
}
wpa_s->reassociate = 1;
wpa_supplicant_connect(wpa_s, bss, ssid);
return 0;
}
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len) char *buf, size_t *resp_len)
{ {
@ -1853,6 +1893,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
wpas_notify_resume(wpa_s->global); wpas_notify_resume(wpa_s->global);
} else if (os_strcmp(buf, "DROP_SA") == 0) { } else if (os_strcmp(buf, "DROP_SA") == 0) {
wpa_supplicant_ctrl_iface_drop_sa(wpa_s); wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
} else if (os_strncmp(buf, "ROAM ", 5) == 0) {
if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
reply_len = -1;
} else { } else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16); os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16; reply_len = 16;

View file

@ -720,9 +720,9 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
} }
static void wpa_supplicant_connect(struct wpa_supplicant *wpa_s, void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected, struct wpa_bss *selected,
struct wpa_ssid *ssid) struct wpa_ssid *ssid)
{ {
if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP

View file

@ -1440,6 +1440,26 @@ static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
} }
static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[128];
int res;
if (argc != 1) {
printf("Invalid ROAM command: needs one argument "
"(target AP's BSSID)\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long ROAM command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
enum wpa_cli_cmd_flags { enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00, cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01 cli_cmd_flag_sensitive = 0x01
@ -1640,6 +1660,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
"= notification of resume/thaw" }, "= notification of resume/thaw" },
{ "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none, { "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
"= drop SA without deauth/disassoc (test command)" }, "= drop SA without deauth/disassoc (test command)" },
{ "roam", wpa_cli_cmd_roam,
cli_cmd_flag_none,
"<addr> = roam to the specified BSS" },
{ NULL, NULL, cli_cmd_flag_none, NULL } { NULL, NULL, cli_cmd_flag_none, NULL }
}; };

View file

@ -488,6 +488,9 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
/* events.c */ /* events.c */
void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s); void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected,
struct wpa_ssid *ssid);
/* eap_register.c */ /* eap_register.c */
int eap_register_methods(void); int eap_register_methods(void);