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:
parent
46ab9b8cf0
commit
a8dab08a28
10 changed files with 387 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue