Interworking: Add commands for network selection

This adds the basic mechanism for running through network selection:
scan, ANQP fetch, network selection, and connection. Actual rules for
network selection and the creation of the network block are still
missing, but will be added in separate commits.
This commit is contained in:
Jouni Malinen 2011-10-04 22:13:22 +03:00 committed by Jouni Malinen
parent afc064fe7a
commit b02fe7ff32
6 changed files with 160 additions and 5 deletions

View file

@ -125,6 +125,9 @@ extern "C" {
#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
#define INTERWORKING_AP "INTERWORKING-AP "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
/* hostapd control interface - fixed message prefixes */
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "

View file

@ -2931,6 +2931,27 @@ static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
#ifdef CONFIG_INTERWORKING
static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
{
u8 bssid[ETH_ALEN];
struct wpa_bss *bss;
if (hwaddr_aton(dst, bssid)) {
wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
return -1;
}
bss = wpa_bss_get_bssid(wpa_s, bssid);
if (bss == NULL) {
wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
MAC2STR(bssid));
return -1;
}
return interworking_connect(wpa_s, bss);
}
static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
{
u8 dst_addr[ETH_ALEN];
@ -3262,6 +3283,13 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = -1;
} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
interworking_stop_fetch_anqp(wpa_s);
} else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
NULL) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
if (get_anqp(wpa_s, buf + 9) < 0)
reply_len = -1;

View file

@ -17,9 +17,11 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "wpa_supplicant_i.h"
#include "bss.h"
#include "scan.h"
#include "gas_query.h"
#include "interworking.h"
@ -108,6 +110,46 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
}
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
if (bss == NULL)
return -1;
wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
MAC2STR(bss->bssid));
/* TODO: create network block and connect */
return 0;
}
static void interworking_select_network(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss, *selected = NULL;
unsigned int count = 0;
wpa_s->network_select = 0;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (bss->anqp_nai_realm == NULL)
continue;
/* TODO: verify that matching credentials are available */
count++;
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR,
MAC2STR(bss->bssid));
if (selected == NULL && wpa_s->auto_select)
selected = bss;
}
if (count == 0) {
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
"with matching credentials found");
}
if (selected)
interworking_connect(wpa_s, selected);
}
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
@ -137,22 +179,32 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
if (found == 0) {
wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
wpa_s->fetch_anqp_in_progress = 0;
if (wpa_s->network_select)
interworking_select_network(wpa_s);
}
}
int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
if (wpa_s->fetch_anqp_in_progress)
return 0;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
wpa_s->fetch_anqp_in_progress = 1;
interworking_next_anqp_fetch(wpa_s);
}
int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
{
if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
return 0;
wpa_s->network_select = 0;
interworking_start_fetch_anqp(wpa_s);
return 0;
}
@ -351,3 +403,27 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
pos += slen;
}
}
static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
"ANQP fetch");
interworking_start_fetch_anqp(wpa_s);
}
int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
{
interworking_stop_fetch_anqp(wpa_s);
wpa_s->network_select = 1;
wpa_s->auto_select = !!auto_select;
wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
"selection");
wpa_s->scan_res_handler = interworking_scan_res_handler;
wpa_s->scan_req = 2;
wpa_supplicant_req_scan(wpa_s, 0, 0);
return 0;
}

View file

@ -25,5 +25,7 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
const struct wpabuf *resp, u16 status_code);
int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
#endif /* INTERWORKING_H */

View file

@ -2234,6 +2234,44 @@ static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
}
static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[100];
int res;
if (argc == 0)
return wpa_ctrl_command(ctrl, "INTERWORKING_SELECT");
res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_SELECT %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[100];
int res;
if (argc != 1) {
printf("Invalid INTERWORKING_CONNECT commands: needs one "
"argument (BSSID)\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_CONNECT %s",
argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[100];
@ -2655,6 +2693,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
"= fetch ANQP information for all APs" },
{ "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none,
"= stop fetch_anqp operation" },
{ "interworking_select", wpa_cli_cmd_interworking_select,
cli_cmd_flag_none,
"[auto] = perform Interworking network selection" },
{ "interworking_connect", wpa_cli_cmd_interworking_connect,
cli_cmd_flag_none,
"<BSSID> = connect using Interworking credentials" },
{ "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
"<addr> <info id>[,<info id>]... = request ANQP information" },
#endif /* CONFIG_INTERWORKING */

View file

@ -591,7 +591,9 @@ struct wpa_supplicant {
struct gas_query *gas;
#ifdef CONFIG_INTERWORKING
int fetch_anqp_in_progress;
int fetch_anqp_in_progress:1;
int network_select:1;
int auto_select:1;
#endif /* CONFIG_INTERWORKING */
};