FST: Testing support

This patch introduces infrastructure needed for FST module tests.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Anton Nayshtut 2014-12-04 19:20:56 +02:00 committed by Jouni Malinen
parent 46ab9b8cf0
commit a8dab08a28
10 changed files with 387 additions and 0 deletions

View file

@ -260,6 +260,9 @@ OBJS += src/fst/fst_group.c
OBJS += src/fst/fst_iface.c OBJS += src/fst/fst_iface.c
OBJS += src/fst/fst_session.c OBJS += src/fst/fst_session.c
OBJS += src/fst/fst_ctrl_aux.c OBJS += src/fst/fst_ctrl_aux.c
ifdef CONFIG_FST_TEST
L_CFLAGS += -DCONFIG_FST_TEST
endif
ifndef CONFIG_NO_CTRL_IFACE ifndef CONFIG_NO_CTRL_IFACE
OBJS += src/fst/fst_ctrl_iface.c OBJS += src/fst/fst_ctrl_iface.c
endif endif

View file

@ -905,6 +905,9 @@ OBJS += ../src/fst/fst_group.o
OBJS += ../src/fst/fst_iface.o OBJS += ../src/fst/fst_iface.o
OBJS += ../src/fst/fst_session.o OBJS += ../src/fst/fst_session.o
OBJS += ../src/fst/fst_ctrl_aux.o OBJS += ../src/fst/fst_ctrl_aux.o
ifdef CONFIG_FST_TEST
CFLAGS += -DCONFIG_FST_TEST
endif
ifndef CONFIG_NO_CTRL_IFACE ifndef CONFIG_NO_CTRL_IFACE
OBJS += ../src/fst/fst_ctrl_iface.o OBJS += ../src/fst/fst_ctrl_iface.o
endif endif

View file

@ -286,6 +286,9 @@ CONFIG_IPV6=y
# Enable Fast Session Transfer (FST) # Enable Fast Session Transfer (FST)
#CONFIG_FST=y #CONFIG_FST=y
# Enable CLI commands for FST testing
#CONFIG_FST_TEST=y
# Testing options # Testing options
# This can be used to enable some testing options (see also the example # This can be used to enable some testing options (see also the example
# configuration file) that are really useful only for testing clients that # configuration file) that are really useful only for testing clients that

View file

@ -67,6 +67,20 @@
#define FST_CMD_SESSION_TRANSFER "session_transfer" #define FST_CMD_SESSION_TRANSFER "session_transfer"
#define FST_CMD_SESSION_TEARDOWN "session_teardown" #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 */ /* Events */
#define FST_CTRL_EVENT_IFACE "FST-EVENT-IFACE" #define FST_CTRL_EVENT_IFACE "FST-EVENT-IFACE"
#define FST_CEI_PNAME_IFNAME "ifname" #define FST_CEI_PNAME_IFNAME "ifname"

View 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"); 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 */ /* fst list_sessions */
struct list_sessions_cb_ctx { struct list_sessions_cb_ctx {
char *buf; 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_RESPOND, 1, session_respond},
{ FST_CMD_SESSION_TRANSFER, 1, session_transfer}, { FST_CMD_SESSION_TRANSFER, 1, session_transfer},
{ FST_CMD_SESSION_TEARDOWN, 1, session_teardown}, { 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 } { NULL, 0, NULL }
}; };
const struct fst_command *c; const struct fst_command *c;

View file

@ -14,6 +14,9 @@
#include "fst/fst_internal.h" #include "fst/fst_internal.h"
#include "fst/fst_defs.h" #include "fst/fst_defs.h"
#include "fst/fst_ctrl_iface.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 #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; 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 */

View file

@ -62,4 +62,19 @@ int fst_session_set_str_peer_addr(struct fst_session *s, const char *mac,
Boolean is_old); Boolean is_old);
int fst_session_set_str_llt(struct fst_session *s, const char *llt_str); 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 */ #endif /* FST_SESSION_H */

View file

@ -323,6 +323,9 @@ OBJS += src/fst/fst_session.c
OBJS += src/fst/fst_iface.c OBJS += src/fst/fst_iface.c
OBJS += src/fst/fst_group.c OBJS += src/fst/fst_group.c
OBJS += src/fst/fst_ctrl_aux.c OBJS += src/fst/fst_ctrl_aux.c
ifdef CONFIG_FST_TEST
L_CFLAGS += -DCONFIG_FST_TEST
endif
ifdef CONFIG_CTRL_IFACE ifdef CONFIG_CTRL_IFACE
OBJS += src/fst/fst_ctrl_iface.c OBJS += src/fst/fst_ctrl_iface.c
endif endif

View file

@ -1593,6 +1593,9 @@ endif
ifdef CONFIG_FST ifdef CONFIG_FST
CFLAGS += -DCONFIG_FST CFLAGS += -DCONFIG_FST
ifdef CONFIG_FST_TEST
CFLAGS += -DCONFIG_FST_TEST
endif
FST_OBJS += ../src/fst/fst.o FST_OBJS += ../src/fst/fst.o
FST_OBJS += ../src/fst/fst_session.o FST_OBJS += ../src/fst/fst_session.o
FST_OBJS += ../src/fst/fst_iface.o FST_OBJS += ../src/fst/fst_iface.o

View file

@ -498,3 +498,6 @@ CONFIG_PEERKEY=y
# Enable Fast Session Transfer (FST) # Enable Fast Session Transfer (FST)
#CONFIG_FST=y #CONFIG_FST=y
# Enable CLI commands for FST testing
#CONFIG_FST_TEST=y