Add INTERWORKING_ADD_NETWORK command

This can be used to provide more control to upper layers on network
blocks generated as part of Interworking network selection.
INTERWORKING_ADD_NETWORK behaves otherwise identically to
INTERWORKING_CONNECT, but it does not request a new connection after
having added the network block and it returns the network id of the
added network.

INTERWORKING_ADD_NETWORK followed by REASSOCIATE would behave more or
less identically to INTERWORKING_CONNECT, but this allows the created
network profile to be modified, if desired, and/or stored externally.
SELECT_NETWORK can also be used with the network id returned from
INTERWORKING_ADD_NETWORK to enforce that specific network profile to be
used for the next connection (though, it should be noted that this
behavior may not meet all Hotspot 2.0 requirements if there were other
enabled networks that could have higher priority).

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2015-02-08 16:56:04 +02:00
parent c612ae97a4
commit f91a512f1f
4 changed files with 49 additions and 20 deletions

View file

@ -5946,7 +5946,8 @@ static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
} }
static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst) static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
int only_add)
{ {
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
struct wpa_bss *bss; struct wpa_bss *bss;
@ -5984,7 +5985,7 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
"Found another matching BSS entry with SSID"); "Found another matching BSS entry with SSID");
} }
return interworking_connect(wpa_s, bss); return interworking_connect(wpa_s, bss, only_add);
} }
@ -8119,8 +8120,19 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (ctrl_interworking_select(wpa_s, buf + 20) < 0) if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
reply_len = -1; reply_len = -1;
} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) { } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
if (ctrl_interworking_connect(wpa_s, buf + 21) < 0) if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0)
reply_len = -1; reply_len = -1;
} else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) {
int id;
id = ctrl_interworking_connect(wpa_s, buf + 25, 1);
if (id < 0)
reply_len = -1;
else {
reply_len = os_snprintf(reply, reply_size, "%d\n", id);
if (os_snprintf_error(reply_size, reply_len))
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;

View file

@ -955,7 +955,7 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred, struct wpa_cred *cred,
struct wpa_bss *bss) struct wpa_bss *bss, int only_add)
{ {
#ifdef INTERWORKING_3GPP #ifdef INTERWORKING_3GPP
struct wpa_ssid *ssid; struct wpa_ssid *ssid;
@ -972,7 +972,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
if (already_connected(wpa_s, cred, bss)) { if (already_connected(wpa_s, cred, bss)) {
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
MAC2STR(bss->bssid)); MAC2STR(bss->bssid));
return 0; return wpa_s->current_ssid->id;
} }
remove_duplicate_network(wpa_s, cred, bss); remove_duplicate_network(wpa_s, cred, bss);
@ -1049,9 +1049,10 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
wpa_s->next_ssid = ssid; wpa_s->next_ssid = ssid;
wpa_config_update_prio_list(wpa_s->conf); wpa_config_update_prio_list(wpa_s->conf);
interworking_reconnect(wpa_s); if (!only_add)
interworking_reconnect(wpa_s);
return 0; return ssid->id;
fail: fail:
wpas_notify_network_removed(wpa_s, ssid); wpas_notify_network_removed(wpa_s, ssid);
@ -1499,7 +1500,7 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid,
static int interworking_connect_roaming_consortium( static int interworking_connect_roaming_consortium(
struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
struct wpa_bss *bss) struct wpa_bss *bss, int only_add)
{ {
struct wpa_ssid *ssid; struct wpa_ssid *ssid;
@ -1509,7 +1510,7 @@ static int interworking_connect_roaming_consortium(
if (already_connected(wpa_s, cred, bss)) { if (already_connected(wpa_s, cred, bss)) {
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
MAC2STR(bss->bssid)); MAC2STR(bss->bssid));
return 0; return wpa_s->current_ssid->id;
} }
remove_duplicate_network(wpa_s, cred, bss); remove_duplicate_network(wpa_s, cred, bss);
@ -1545,9 +1546,10 @@ static int interworking_connect_roaming_consortium(
wpa_s->next_ssid = ssid; wpa_s->next_ssid = ssid;
wpa_config_update_prio_list(wpa_s->conf); wpa_config_update_prio_list(wpa_s->conf);
interworking_reconnect(wpa_s); if (!only_add)
interworking_reconnect(wpa_s);
return 0; return ssid->id;
fail: fail:
wpas_notify_network_removed(wpa_s, ssid); wpas_notify_network_removed(wpa_s, ssid);
@ -1557,7 +1559,8 @@ fail:
static int interworking_connect_helper(struct wpa_supplicant *wpa_s, static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, int allow_excluded) struct wpa_bss *bss, int allow_excluded,
int only_add)
{ {
struct wpa_cred *cred, *cred_rc, *cred_3gpp; struct wpa_cred *cred, *cred_rc, *cred_3gpp;
struct wpa_ssid *ssid; struct wpa_ssid *ssid;
@ -1659,11 +1662,12 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
(cred == NULL || cred_prio_cmp(cred_rc, cred) >= 0) && (cred == NULL || cred_prio_cmp(cred_rc, cred) >= 0) &&
(cred_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0)) (cred_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0))
return interworking_connect_roaming_consortium(wpa_s, cred_rc, return interworking_connect_roaming_consortium(wpa_s, cred_rc,
bss); bss, only_add);
if (cred_3gpp && if (cred_3gpp &&
(cred == NULL || cred_prio_cmp(cred_3gpp, cred) >= 0)) { (cred == NULL || cred_prio_cmp(cred_3gpp, cred) >= 0)) {
return interworking_connect_3gpp(wpa_s, cred_3gpp, bss); return interworking_connect_3gpp(wpa_s, cred_3gpp, bss,
only_add);
} }
if (cred == NULL) { if (cred == NULL) {
@ -1801,9 +1805,10 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_s->next_ssid = ssid; wpa_s->next_ssid = ssid;
wpa_config_update_prio_list(wpa_s->conf); wpa_config_update_prio_list(wpa_s->conf);
interworking_reconnect(wpa_s); if (!only_add)
interworking_reconnect(wpa_s);
return 0; return ssid->id;
fail: fail:
wpas_notify_network_removed(wpa_s, ssid); wpas_notify_network_removed(wpa_s, ssid);
@ -1813,9 +1818,10 @@ fail:
} }
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
int only_add)
{ {
return interworking_connect_helper(wpa_s, bss, 1); return interworking_connect_helper(wpa_s, bss, 1, only_add);
} }
@ -2495,7 +2501,7 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
MAC2STR(selected->bssid)); MAC2STR(selected->bssid));
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR, wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR,
MAC2STR(selected->bssid)); MAC2STR(selected->bssid));
interworking_connect(wpa_s, selected); interworking_connect(wpa_s, selected, 0);
} }
} }

View file

@ -24,7 +24,8 @@ 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_select(struct wpa_supplicant *wpa_s, int auto_select,
int *freqs); int *freqs);
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
int only_add);
void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s); void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred, struct wpa_cred *cred,

View file

@ -2309,6 +2309,13 @@ static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
} }
static int wpa_cli_cmd_interworking_add_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_cli_cmd(ctrl, "INTERWORKING_ADD_NETWORK", 1, argc, argv);
}
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[])
{ {
return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv); return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
@ -2997,6 +3004,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "interworking_connect", wpa_cli_cmd_interworking_connect, { "interworking_connect", wpa_cli_cmd_interworking_connect,
wpa_cli_complete_bss, cli_cmd_flag_none, wpa_cli_complete_bss, cli_cmd_flag_none,
"<BSSID> = connect using Interworking credentials" }, "<BSSID> = connect using Interworking credentials" },
{ "interworking_add_network", wpa_cli_cmd_interworking_add_network,
wpa_cli_complete_bss, cli_cmd_flag_none,
"<BSSID> = connect using Interworking credentials" },
{ "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss, { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
cli_cmd_flag_none, cli_cmd_flag_none,
"<addr> <info id>[,<info id>]... = request ANQP information" }, "<addr> <info id>[,<info id>]... = request ANQP information" },