aboutsummaryrefslogtreecommitdiffstats
path: root/src/fst
diff options
context:
space:
mode:
authorAnton Nayshtut <qca_antonn@qca.qualcomm.com>2014-12-04 17:20:56 (GMT)
committerJouni Malinen <j@w1.fi>2015-07-16 15:26:16 (GMT)
commita8dab08a2887cca4faeebf355b41ecc4f69264ba (patch)
tree8ba79be1ff159d9a7d217827b488884ee318b247 /src/fst
parent46ab9b8cf07a16b6e6d50b59bafc8ce553822a26 (diff)
downloadhostap-a8dab08a2887cca4faeebf355b41ecc4f69264ba.zip
hostap-a8dab08a2887cca4faeebf355b41ecc4f69264ba.tar.gz
hostap-a8dab08a2887cca4faeebf355b41ecc4f69264ba.tar.bz2
FST: Testing support
This patch introduces infrastructure needed for FST module tests. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Diffstat (limited to 'src/fst')
-rw-r--r--src/fst/fst_ctrl_defs.h14
-rw-r--r--src/fst/fst_ctrl_iface.c55
-rw-r--r--src/fst/fst_session.c285
-rw-r--r--src/fst/fst_session.h15
4 files changed, 369 insertions, 0 deletions
diff --git a/src/fst/fst_ctrl_defs.h b/src/fst/fst_ctrl_defs.h
index 0e883b1..6735389 100644
--- a/src/fst/fst_ctrl_defs.h
+++ b/src/fst/fst_ctrl_defs.h
@@ -67,6 +67,20 @@
#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"
diff --git a/src/fst/fst_ctrl_iface.c b/src/fst/fst_ctrl_iface.c
index 6d7887e..db68bb5 100644
--- a/src/fst/fst_ctrl_iface.c
+++ b/src/fst/fst_ctrl_iface.c
@@ -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;
diff --git a/src/fst/fst_session.c b/src/fst/fst_session.c
index da994d8..0f5d726 100644
--- a/src/fst/fst_session.c
+++ b/src/fst/fst_session.c
@@ -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 */
diff --git a/src/fst/fst_session.h b/src/fst/fst_session.h
index 4370d2c..1162de4 100644
--- a/src/fst/fst_session.h
+++ b/src/fst/fst_session.h
@@ -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 */