]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FST: Testing support
authorAnton Nayshtut <qca_antonn@qca.qualcomm.com>
Thu, 4 Dec 2014 17:20:56 +0000 (19:20 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 16 Jul 2015 15:26:16 +0000 (18:26 +0300)
This patch introduces infrastructure needed for FST module tests.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
hostapd/Android.mk
hostapd/Makefile
hostapd/defconfig
src/fst/fst_ctrl_defs.h
src/fst/fst_ctrl_iface.c
src/fst/fst_session.c
src/fst/fst_session.h
wpa_supplicant/Android.mk
wpa_supplicant/Makefile
wpa_supplicant/defconfig

index 31dec1750d3e49bfb0161d7c8341f17ec68542be..f2c498dd36ae5538bda76d3044919b11597a35f0 100644 (file)
@@ -260,6 +260,9 @@ OBJS += src/fst/fst_group.c
 OBJS += src/fst/fst_iface.c
 OBJS += src/fst/fst_session.c
 OBJS += src/fst/fst_ctrl_aux.c
+ifdef CONFIG_FST_TEST
+L_CFLAGS += -DCONFIG_FST_TEST
+endif
 ifndef CONFIG_NO_CTRL_IFACE
 OBJS += src/fst/fst_ctrl_iface.c
 endif
index c543d66743f80ac5bea272e36297f23c12e01363..086a6412e48427a91645d12fda42198ee1c20018 100644 (file)
@@ -905,6 +905,9 @@ OBJS += ../src/fst/fst_group.o
 OBJS += ../src/fst/fst_iface.o
 OBJS += ../src/fst/fst_session.o
 OBJS += ../src/fst/fst_ctrl_aux.o
+ifdef CONFIG_FST_TEST
+CFLAGS += -DCONFIG_FST_TEST
+endif
 ifndef CONFIG_NO_CTRL_IFACE
 OBJS += ../src/fst/fst_ctrl_iface.o
 endif
index f8c6a7dcc91d8b73109bc9220ad050848d85a1fc..62a0edeea61c3dc6f2cef0a25c56096f54780539 100644 (file)
@@ -286,6 +286,9 @@ CONFIG_IPV6=y
 # Enable Fast Session Transfer (FST)
 #CONFIG_FST=y
 
+# Enable CLI commands for FST testing
+#CONFIG_FST_TEST=y
+
 # Testing options
 # This can be used to enable some testing options (see also the example
 # configuration file) that are really useful only for testing clients that
index 0e883b1c044f2cb034a296efe0e81d2cd9cc3277..67353890ffcf9f50d1ec9b6871128a195b54c211 100644 (file)
 #define FST_CMD_SESSION_TRANSFER "session_transfer"
 #define FST_CMD_SESSION_TEARDOWN "session_teardown"
 
+#ifdef CONFIG_FST_TEST
+#define FST_CTR_PVAL_BAD_NEW_BAND        "bad_new_band"
+
+#define FST_CMD_TEST_REQUEST    "test_request"
+#define FST_CTR_IS_SUPPORTED        "is_supported"
+#define FST_CTR_SEND_SETUP_REQUEST  "send_setup_request"
+#define FST_CTR_SEND_SETUP_RESPONSE "send_setup_response"
+#define FST_CTR_SEND_ACK_REQUEST    "send_ack_request"
+#define FST_CTR_SEND_ACK_RESPONSE   "send_ack_response"
+#define FST_CTR_SEND_TEAR_DOWN      "send_tear_down"
+#define FST_CTR_GET_FSTS_ID         "get_fsts_id"
+#define FST_CTR_GET_LOCAL_MBIES     "get_local_mbies"
+#endif /* CONFIG_FST_TEST */
+
 /* Events */
 #define FST_CTRL_EVENT_IFACE "FST-EVENT-IFACE"
 #define FST_CEI_PNAME_IFNAME       "ifname"
index 6d7887e564149327f3d3adf63fde6e4432b361f9..db68bb50ca0f16d816c68ec0125ef980698798a5 100644 (file)
@@ -408,6 +408,58 @@ static int session_teardown(const char *session_id, char *buf, size_t buflen)
        return os_snprintf(buf, buflen, "OK\n");
 }
 
+
+#ifdef CONFIG_FST_TEST
+/* fst test_request */
+static int test_request(const char *request, char *buf, size_t buflen)
+{
+       const char *p = request;
+       int ret;
+
+       if (!os_strncasecmp(p, FST_CTR_SEND_SETUP_REQUEST,
+                           os_strlen(FST_CTR_SEND_SETUP_REQUEST))) {
+               ret = fst_test_req_send_fst_request(
+                       p + os_strlen(FST_CTR_SEND_SETUP_REQUEST));
+       } else if (!os_strncasecmp(p, FST_CTR_SEND_SETUP_RESPONSE,
+                                  os_strlen(FST_CTR_SEND_SETUP_RESPONSE))) {
+               ret = fst_test_req_send_fst_response(
+                       p + os_strlen(FST_CTR_SEND_SETUP_RESPONSE));
+       } else if (!os_strncasecmp(p, FST_CTR_SEND_ACK_REQUEST,
+                                  os_strlen(FST_CTR_SEND_ACK_REQUEST))) {
+               ret = fst_test_req_send_ack_request(
+                       p + os_strlen(FST_CTR_SEND_ACK_REQUEST));
+       } else if (!os_strncasecmp(p, FST_CTR_SEND_ACK_RESPONSE,
+                                  os_strlen(FST_CTR_SEND_ACK_RESPONSE))) {
+               ret = fst_test_req_send_ack_response(
+                       p + os_strlen(FST_CTR_SEND_ACK_RESPONSE));
+       } else if (!os_strncasecmp(p, FST_CTR_SEND_TEAR_DOWN,
+                                  os_strlen(FST_CTR_SEND_TEAR_DOWN))) {
+               ret = fst_test_req_send_tear_down(
+                       p + os_strlen(FST_CTR_SEND_TEAR_DOWN));
+       } else if (!os_strncasecmp(p, FST_CTR_GET_FSTS_ID,
+                                  os_strlen(FST_CTR_GET_FSTS_ID))) {
+               u32 fsts_id = fst_test_req_get_fsts_id(
+                       p + os_strlen(FST_CTR_GET_FSTS_ID));
+               if (fsts_id != FST_FSTS_ID_NOT_FOUND)
+                       return os_snprintf(buf, buflen, "%u\n", fsts_id);
+               return os_snprintf(buf, buflen, "FAIL\n");
+       } else if (!os_strncasecmp(p, FST_CTR_GET_LOCAL_MBIES,
+                                  os_strlen(FST_CTR_GET_LOCAL_MBIES))) {
+               return fst_test_req_get_local_mbies(
+                       p + os_strlen(FST_CTR_GET_LOCAL_MBIES), buf, buflen);
+       } else if (!os_strncasecmp(p, FST_CTR_IS_SUPPORTED,
+                                  os_strlen(FST_CTR_IS_SUPPORTED))) {
+               ret = 0;
+       } else {
+               fst_printf(MSG_ERROR, "CTRL: Unknown parameter: %s", p);
+               return os_snprintf(buf, buflen, "FAIL\n");
+       }
+
+       return os_snprintf(buf, buflen, "%s\n", ret ? "FAIL" : "OK");
+}
+#endif /* CONFIG_FST_TEST */
+
+
 /* fst list_sessions */
 struct list_sessions_cb_ctx {
        char *buf;
@@ -752,6 +804,9 @@ int fst_ctrl_iface_receive(const char *cmd, char *reply, size_t reply_size)
                { FST_CMD_SESSION_RESPOND, 1, session_respond},
                { FST_CMD_SESSION_TRANSFER, 1, session_transfer},
                { FST_CMD_SESSION_TEARDOWN, 1, session_teardown},
+#ifdef CONFIG_FST_TEST
+               { FST_CMD_TEST_REQUEST, 1, test_request },
+#endif /* CONFIG_FST_TEST */
                { NULL, 0, NULL }
        };
        const struct fst_command *c;
index da994d8ea42d4c97b9d9df331c9b90cea23ec679..0f5d726070ae649336193f2e567aa3f581eefbd9 100644 (file)
@@ -14,6 +14,9 @@
 #include "fst/fst_internal.h"
 #include "fst/fst_defs.h"
 #include "fst/fst_ctrl_iface.h"
+#ifdef CONFIG_FST_TEST
+#include "fst/fst_ctrl_defs.h"
+#endif /* CONFIG_FST_TEST */
 
 #define US_80211_TU 1024
 
@@ -1272,3 +1275,285 @@ struct fst_session * fst_session_global_get_first_by_group(struct fst_group *g)
        return NULL;
 }
 
+
+#ifdef CONFIG_FST_TEST
+
+static int get_group_fill_session(struct fst_group **g, struct fst_session *s)
+{
+       const u8 *old_addr, *new_addr;
+       struct fst_get_peer_ctx *ctx;
+
+       os_memset(s, 0, sizeof(*s));
+       *g = dl_list_first(&fst_global_groups_list,
+                          struct fst_group, global_groups_lentry);
+       if (!*g)
+               return EINVAL;
+
+       s->data.new_iface = dl_list_first(&(*g)->ifaces, struct fst_iface,
+                                         group_lentry);
+       if (!s->data.new_iface)
+               return EINVAL;
+
+       s->data.old_iface = dl_list_entry(s->data.new_iface->group_lentry.next,
+                                         struct fst_iface, group_lentry);
+       if (!s->data.old_iface)
+               return EINVAL;
+
+       old_addr = fst_iface_get_peer_first(s->data.old_iface, &ctx, TRUE);
+       if (!old_addr)
+               return EINVAL;
+
+       new_addr = fst_iface_get_peer_first(s->data.new_iface, &ctx, TRUE);
+       if (!new_addr)
+               return EINVAL;
+
+       os_memcpy(s->data.old_peer_addr, old_addr, ETH_ALEN);
+       os_memcpy(s->data.new_peer_addr, new_addr, ETH_ALEN);
+
+       return 0;
+}
+
+
+#define FST_MAX_COMMAND_WORD_NAME_LENGTH 16
+
+int fst_test_req_send_fst_request(const char *params)
+{
+       int fsts_id;
+       Boolean is_valid;
+       char *endp;
+       struct fst_setup_req req;
+       struct fst_session s;
+       struct fst_group *g;
+       enum hostapd_hw_mode hw_mode;
+       u8 channel;
+       char additional_param[FST_MAX_COMMAND_WORD_NAME_LENGTH];
+
+       fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
+       if (!is_valid)
+               return EINVAL;
+
+       if (get_group_fill_session(&g, &s))
+               return EINVAL;
+
+       req.action = FST_ACTION_SETUP_REQUEST;
+       req.dialog_token = g->dialog_token;
+       req.llt = host_to_le32(FST_LLT_MS_DEFAULT);
+       /* 8.4.2.147 Session Transition element */
+       req.stie.element_id = WLAN_EID_SESSION_TRANSITION;
+       req.stie.length = sizeof(req.stie);
+       req.stie.fsts_id = host_to_le32(fsts_id);
+       req.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
+
+       fst_iface_get_channel_info(s.data.new_iface, &hw_mode, &channel);
+       req.stie.new_band_id = fst_hw_mode_to_band(hw_mode);
+       req.stie.new_band_op = 1;
+       req.stie.new_band_setup = 0;
+
+       fst_iface_get_channel_info(s.data.old_iface, &hw_mode, &channel);
+       req.stie.old_band_id = fst_hw_mode_to_band(hw_mode);
+       req.stie.old_band_op = 1;
+       req.stie.old_band_setup = 0;
+
+       if (!fst_read_next_text_param(endp, additional_param,
+                                      sizeof(additional_param), &endp)) {
+               if (!os_strcasecmp(additional_param, FST_CTR_PVAL_BAD_NEW_BAND))
+                       req.stie.new_band_id = req.stie.old_band_id;
+       }
+
+       return fst_session_send_action(&s, TRUE, &req, sizeof(req),
+                                      s.data.old_iface->mb_ie);
+}
+
+
+int fst_test_req_send_fst_response(const char *params)
+{
+       int fsts_id;
+       Boolean is_valid;
+       char *endp;
+       struct fst_setup_res res;
+       struct fst_session s;
+       struct fst_group *g;
+       enum hostapd_hw_mode hw_mode;
+       u8 status_code;
+       u8 channel;
+       char response[FST_MAX_COMMAND_WORD_NAME_LENGTH];
+       struct fst_session *_s;
+
+       fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
+       if (!is_valid)
+               return EINVAL;
+
+       if (get_group_fill_session(&g, &s))
+               return EINVAL;
+
+       status_code = WLAN_STATUS_SUCCESS;
+       if (!fst_read_next_text_param(endp, response, sizeof(response),
+                                     &endp)) {
+               if (!os_strcasecmp(response, FST_CS_PVAL_RESPONSE_REJECT))
+                       status_code = WLAN_STATUS_PENDING_ADMITTING_FST_SESSION;
+       }
+
+       os_memset(&res, 0, sizeof(res));
+
+       res.action = FST_ACTION_SETUP_RESPONSE;
+       /*
+        * If some session has just received an FST Setup Request, then
+        * use the correct dialog token copied from this request.
+        */
+       _s = fst_find_session_in_progress(fst_session_get_peer_addr(&s, TRUE),
+                                         g);
+       res.dialog_token = (_s && fst_session_is_ready_pending(_s)) ?
+               _s->data.pending_setup_req_dlgt : g->dialog_token;
+       res.status_code  = status_code;
+
+       if (res.status_code == WLAN_STATUS_SUCCESS) {
+               res.stie.element_id = WLAN_EID_SESSION_TRANSITION;
+               res.stie.length = sizeof(res.stie);
+               res.stie.fsts_id = fsts_id;
+               res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
+
+               fst_iface_get_channel_info(s.data.new_iface, &hw_mode,
+                                           &channel);
+               res.stie.new_band_id = fst_hw_mode_to_band(hw_mode);
+               res.stie.new_band_op = 1;
+               res.stie.new_band_setup = 0;
+
+               fst_iface_get_channel_info(s.data.old_iface, &hw_mode,
+                                          &channel);
+               res.stie.old_band_id = fst_hw_mode_to_band(hw_mode);
+               res.stie.old_band_op = 1;
+               res.stie.old_band_setup = 0;
+       }
+
+       if (!fst_read_next_text_param(endp, response, sizeof(response),
+                                     &endp)) {
+               if (!os_strcasecmp(response, FST_CTR_PVAL_BAD_NEW_BAND))
+                       res.stie.new_band_id = res.stie.old_band_id;
+       }
+
+       return fst_session_send_action(&s, TRUE, &res, sizeof(res),
+                                      s.data.old_iface->mb_ie);
+}
+
+
+int fst_test_req_send_ack_request(const char *params)
+{
+       int fsts_id;
+       Boolean is_valid;
+       char *endp;
+       struct fst_ack_req req;
+       struct fst_session s;
+       struct fst_group *g;
+
+       fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
+       if (!is_valid)
+               return EINVAL;
+
+       if (get_group_fill_session(&g, &s))
+               return EINVAL;
+
+       os_memset(&req, 0, sizeof(req));
+       req.action = FST_ACTION_ACK_REQUEST;
+       req.dialog_token = g->dialog_token;
+       req.fsts_id = fsts_id;
+
+       return fst_session_send_action(&s, FALSE, &req, sizeof(req), NULL);
+}
+
+
+int fst_test_req_send_ack_response(const char *params)
+{
+       int fsts_id;
+       Boolean is_valid;
+       char *endp;
+       struct fst_ack_res res;
+       struct fst_session s;
+       struct fst_group *g;
+
+       fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
+       if (!is_valid)
+               return EINVAL;
+
+       if (get_group_fill_session(&g, &s))
+               return EINVAL;
+
+       os_memset(&res, 0, sizeof(res));
+       res.action = FST_ACTION_ACK_RESPONSE;
+       res.dialog_token = g->dialog_token;
+       res.fsts_id = fsts_id;
+
+       return fst_session_send_action(&s, FALSE, &res, sizeof(res), NULL);
+}
+
+
+int fst_test_req_send_tear_down(const char *params)
+{
+       int fsts_id;
+       Boolean is_valid;
+       char *endp;
+       struct fst_tear_down td;
+       struct fst_session s;
+       struct fst_group *g;
+
+       fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
+       if (!is_valid)
+               return EINVAL;
+
+       if (get_group_fill_session(&g, &s))
+               return EINVAL;
+
+       os_memset(&td, 0, sizeof(td));
+       td.action = FST_ACTION_TEAR_DOWN;
+       td.fsts_id = fsts_id;
+
+       return fst_session_send_action(&s, TRUE, &td, sizeof(td), NULL);
+}
+
+
+u32 fst_test_req_get_fsts_id(const char *params)
+{
+       int sid;
+       Boolean is_valid;
+       char *endp;
+       struct fst_session *s;
+
+       sid = fst_read_next_int_param(params, &is_valid, &endp);
+       if (!is_valid)
+               return FST_FSTS_ID_NOT_FOUND;
+
+       s = fst_session_get_by_id(sid);
+       if (!s)
+               return FST_FSTS_ID_NOT_FOUND;
+
+       return s->data.fsts_id;
+}
+
+
+int fst_test_req_get_local_mbies(const char *request, char *buf, size_t buflen)
+{
+       char *endp;
+       char ifname[FST_MAX_COMMAND_WORD_NAME_LENGTH];
+       struct fst_group *g;
+       struct fst_iface *iface;
+       int ret;
+
+       if (fst_read_next_text_param(request, ifname, sizeof(ifname), &endp) ||
+           !*ifname)
+               goto problem;
+       g = dl_list_first(&fst_global_groups_list, struct fst_group,
+                         global_groups_lentry);
+       if (!g)
+               goto problem;
+       iface = fst_group_get_iface_by_name(g, ifname);
+       if (!iface || !iface->mb_ie)
+               goto problem;
+       ret = print_mb_ies(iface->mb_ie, buf, buflen);
+       if ((size_t) ret != wpabuf_len(iface->mb_ie) * 2)
+               fst_printf(MSG_WARNING, "MB IEs copied only partially");
+       return ret;
+
+problem:
+       return os_snprintf(buf, buflen, "FAIL\n");
+}
+
+#endif /* CONFIG_FST_TEST */
index 4370d2cbfeac8c929ce567ad81ed3be43f71f1e8..1162de4b367a189f28093fc6c09270394db9c713 100644 (file)
@@ -62,4 +62,19 @@ int fst_session_set_str_peer_addr(struct fst_session *s, const char *mac,
                                  Boolean is_old);
 int fst_session_set_str_llt(struct fst_session *s, const char *llt_str);
 
+#ifdef CONFIG_FST_TEST
+
+#define FST_FSTS_ID_NOT_FOUND ((u32) -1)
+
+int fst_test_req_send_fst_request(const char *params);
+int fst_test_req_send_fst_response(const char *params);
+int fst_test_req_send_ack_request(const char *params);
+int fst_test_req_send_ack_response(const char *params);
+int fst_test_req_send_tear_down(const char *params);
+u32 fst_test_req_get_fsts_id(const char *params);
+int fst_test_req_get_local_mbies(const char *request, char *buf,
+                                size_t buflen);
+
+#endif /* CONFIG_FST_TEST */
+
 #endif /* FST_SESSION_H */
index 65306d23c59fa8e32a2dec75bf3e70beb34e71c5..378d763dfe623dc87141ce00a514de40f9fbf48d 100644 (file)
@@ -323,6 +323,9 @@ OBJS += src/fst/fst_session.c
 OBJS += src/fst/fst_iface.c
 OBJS += src/fst/fst_group.c
 OBJS += src/fst/fst_ctrl_aux.c
+ifdef CONFIG_FST_TEST
+L_CFLAGS += -DCONFIG_FST_TEST
+endif
 ifdef CONFIG_CTRL_IFACE
 OBJS += src/fst/fst_ctrl_iface.c
 endif
index 43e45d563e45a49ecb84701323bdb007953be1b7..a75fc0b4b15e36482573bcfba36243b91f5b34ed 100644 (file)
@@ -1593,6 +1593,9 @@ endif
 
 ifdef CONFIG_FST
 CFLAGS += -DCONFIG_FST
+ifdef CONFIG_FST_TEST
+CFLAGS += -DCONFIG_FST_TEST
+endif
 FST_OBJS += ../src/fst/fst.o
 FST_OBJS += ../src/fst/fst_session.o
 FST_OBJS += ../src/fst/fst_iface.o
index 57672aeeb18dc95dcf3ee04d4f80e2e058d14047..d714a691d7916cee9b189c803ed225e79fefee03 100644 (file)
@@ -498,3 +498,6 @@ CONFIG_PEERKEY=y
 
 # Enable Fast Session Transfer (FST)
 #CONFIG_FST=y
+
+# Enable CLI commands for FST testing
+#CONFIG_FST_TEST=y