]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Interworking: Add commands for network selection
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 4 Oct 2011 19:13:22 +0000 (22:13 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 16 Oct 2011 20:55:34 +0000 (23:55 +0300)
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.

src/common/wpa_ctrl.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/interworking.c
wpa_supplicant/interworking.h
wpa_supplicant/wpa_cli.c
wpa_supplicant/wpa_supplicant_i.h

index 528cc1602c519cb85d9dcfd0c28b9d9d4fd9c2d5..1d1e3d03815adb0d4ba9eea02b15c169a70fca9e 100644 (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 "
index ec1de2ba38becd3002d5ee0bbf0294aef5a77940..512100432423a391c7520c35daf20e5a307373fc 100644 (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;
index 5259c34a2f8a2b6d15d5038f39fcb84e173cd91a..35a3a2b16a4087cbf52e2478fa899b65aaa11b44 100644 (file)
 #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;
+}
index 2a9790bb476c088432a0df877dbb5efdbe009ef0..247df3069458c6bba653e0a75b865128da483dcf 100644 (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 */
index 077d9f14bbbff2ed64b7a2016d09488e6c3e484f..2089df29e8c6abaeaaf4e7a2110bc1169f5e2c32 100644 (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 */
index ff3addf749654ce5f1dc572b19f2b07cdf5e581a..b327f4c65f95386f972bd66e831347a98e4153d9 100644 (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 */
 };