Add INTERWORKING_ADD_NETWORK command
authorJouni Malinen <j@w1.fi>
Sun, 8 Feb 2015 14:56:04 +0000 (16:56 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 8 Feb 2015 20:49:58 +0000 (22:49 +0200)
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>
wpa_supplicant/ctrl_iface.c
wpa_supplicant/interworking.c
wpa_supplicant/interworking.h
wpa_supplicant/wpa_cli.c

index a6ebe3b..0162b6c 100644 (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];
        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");
        }
 
-       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)
                        reply_len = -1;
        } 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;
+       } 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) {
                if (get_anqp(wpa_s, buf + 9) < 0)
                        reply_len = -1;
index 5b66211..0bffe34 100644 (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,
                                     struct wpa_cred *cred,
-                                    struct wpa_bss *bss)
+                                    struct wpa_bss *bss, int only_add)
 {
 #ifdef INTERWORKING_3GPP
        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)) {
                wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
                        MAC2STR(bss->bssid));
-               return 0;
+               return wpa_s->current_ssid->id;
        }
 
        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_config_update_prio_list(wpa_s->conf);
-       interworking_reconnect(wpa_s);
+       if (!only_add)
+               interworking_reconnect(wpa_s);
 
-       return 0;
+       return ssid->id;
 
 fail:
        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(
        struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
-       struct wpa_bss *bss)
+       struct wpa_bss *bss, int only_add)
 {
        struct wpa_ssid *ssid;
 
@@ -1509,7 +1510,7 @@ static int interworking_connect_roaming_consortium(
        if (already_connected(wpa_s, cred, bss)) {
                wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
                        MAC2STR(bss->bssid));
-               return 0;
+               return wpa_s->current_ssid->id;
        }
 
        remove_duplicate_network(wpa_s, cred, bss);
@@ -1545,9 +1546,10 @@ static int interworking_connect_roaming_consortium(
 
        wpa_s->next_ssid = ssid;
        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:
        wpas_notify_network_removed(wpa_s, ssid);
@@ -1557,7 +1559,8 @@ fail:
 
 
 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_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_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0))
                return interworking_connect_roaming_consortium(wpa_s, cred_rc,
-                                                              bss);
+                                                              bss, only_add);
 
        if (cred_3gpp &&
            (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) {
@@ -1801,9 +1805,10 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
 
        wpa_s->next_ssid = ssid;
        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:
        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));
                wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR,
                        MAC2STR(selected->bssid));
-               interworking_connect(wpa_s, selected);
+               interworking_connect(wpa_s, selected, 0);
        }
 }
 
index 38ef745..3743dc0 100644 (file)
@@ -24,7 +24,8 @@ 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 *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);
 int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
                              struct wpa_cred *cred,
index 2f06c35..af08e13 100644 (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[])
 {
        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,
          wpa_cli_complete_bss, cli_cmd_flag_none,
          "<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,
          cli_cmd_flag_none,
          "<addr> <info id>[,<info id>]... = request ANQP information" },