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:
parent
afc064fe7a
commit
b02fe7ff32
6 changed files with 160 additions and 5 deletions
|
@ -125,6 +125,9 @@ extern "C" {
|
||||||
#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
|
#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
|
||||||
#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
|
#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 */
|
/* hostapd control interface - fixed message prefixes */
|
||||||
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
|
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
|
||||||
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
|
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
|
||||||
|
|
|
@ -2931,6 +2931,27 @@ static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_INTERWORKING
|
#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)
|
static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
|
||||||
{
|
{
|
||||||
u8 dst_addr[ETH_ALEN];
|
u8 dst_addr[ETH_ALEN];
|
||||||
|
@ -3262,6 +3283,13 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
|
} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
|
||||||
interworking_stop_fetch_anqp(wpa_s);
|
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) {
|
} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
|
||||||
if (get_anqp(wpa_s, buf + 9) < 0)
|
if (get_anqp(wpa_s, buf + 9) < 0)
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "common/ieee802_11_defs.h"
|
#include "common/ieee802_11_defs.h"
|
||||||
#include "common/gas.h"
|
#include "common/gas.h"
|
||||||
|
#include "common/wpa_ctrl.h"
|
||||||
#include "drivers/driver.h"
|
#include "drivers/driver.h"
|
||||||
#include "wpa_supplicant_i.h"
|
#include "wpa_supplicant_i.h"
|
||||||
#include "bss.h"
|
#include "bss.h"
|
||||||
|
#include "scan.h"
|
||||||
#include "gas_query.h"
|
#include "gas_query.h"
|
||||||
#include "interworking.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)
|
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
|
||||||
{
|
{
|
||||||
struct wpa_bss *bss;
|
struct wpa_bss *bss;
|
||||||
|
@ -137,22 +179,32 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
|
||||||
if (found == 0) {
|
if (found == 0) {
|
||||||
wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
|
wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
|
||||||
wpa_s->fetch_anqp_in_progress = 0;
|
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;
|
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)
|
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
|
||||||
bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
|
bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
|
||||||
|
|
||||||
wpa_s->fetch_anqp_in_progress = 1;
|
wpa_s->fetch_anqp_in_progress = 1;
|
||||||
interworking_next_anqp_fetch(wpa_s);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -351,3 +403,27 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
|
||||||
pos += slen;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -25,5 +25,7 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
|
||||||
const struct wpabuf *resp, u16 status_code);
|
const struct wpabuf *resp, u16 status_code);
|
||||||
int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
|
int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
|
||||||
void interworking_stop_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 */
|
#endif /* INTERWORKING_H */
|
||||||
|
|
|
@ -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[])
|
static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char cmd[100];
|
char cmd[100];
|
||||||
|
@ -2655,6 +2693,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
|
||||||
"= fetch ANQP information for all APs" },
|
"= fetch ANQP information for all APs" },
|
||||||
{ "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none,
|
{ "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none,
|
||||||
"= stop fetch_anqp operation" },
|
"= 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,
|
{ "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
|
||||||
"<addr> <info id>[,<info id>]... = request ANQP information" },
|
"<addr> <info id>[,<info id>]... = request ANQP information" },
|
||||||
#endif /* CONFIG_INTERWORKING */
|
#endif /* CONFIG_INTERWORKING */
|
||||||
|
|
|
@ -591,7 +591,9 @@ struct wpa_supplicant {
|
||||||
struct gas_query *gas;
|
struct gas_query *gas;
|
||||||
|
|
||||||
#ifdef CONFIG_INTERWORKING
|
#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 */
|
#endif /* CONFIG_INTERWORKING */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue