mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-22 06:29:23 +01:00
hwsim: Add support for HWSIM_CMD_GET_RADIO
Add a new option to the hwsim binary to fetch all or a given hwsim radio. Print out radio information which is currently returned in the reply to user space. Add new hwsim attributes to the enum and tweak getopt to behave properly with or without giving the radio id on the command line.
This commit is contained in:
parent
c2a140382a
commit
f1a5dcf6f3
130
tools/hwsim.c
130
tools/hwsim.c
@ -36,6 +36,7 @@ enum {
|
|||||||
HWSIM_CMD_TX_INFO_FRAME,
|
HWSIM_CMD_TX_INFO_FRAME,
|
||||||
HWSIM_CMD_NEW_RADIO,
|
HWSIM_CMD_NEW_RADIO,
|
||||||
HWSIM_CMD_DEL_RADIO,
|
HWSIM_CMD_DEL_RADIO,
|
||||||
|
HWSIM_CMD_GET_RADIO,
|
||||||
__HWSIM_CMD_MAX,
|
__HWSIM_CMD_MAX,
|
||||||
};
|
};
|
||||||
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
|
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
|
||||||
@ -58,6 +59,9 @@ enum {
|
|||||||
HWSIM_ATTR_SUPPORT_P2P_DEVICE,
|
HWSIM_ATTR_SUPPORT_P2P_DEVICE,
|
||||||
HWSIM_ATTR_USE_CHANCTX,
|
HWSIM_ATTR_USE_CHANCTX,
|
||||||
HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE,
|
HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE,
|
||||||
|
HWSIM_ATTR_RADIO_NAME,
|
||||||
|
HWSIM_ATTR_NO_VIF,
|
||||||
|
HWSIM_ATTR_FREQ,
|
||||||
__HWSIM_ATTR_MAX,
|
__HWSIM_ATTR_MAX,
|
||||||
};
|
};
|
||||||
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
|
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
|
||||||
@ -66,6 +70,8 @@ static struct l_genl_family *hwsim;
|
|||||||
|
|
||||||
static bool keep_radios = false;
|
static bool keep_radios = false;
|
||||||
static bool create_action = false;
|
static bool create_action = false;
|
||||||
|
static bool list_action = false;
|
||||||
|
static const char *list_option = NULL;
|
||||||
static const char *destroy_action = NULL;
|
static const char *destroy_action = NULL;
|
||||||
|
|
||||||
static void do_debug(const char *str, void *user_data)
|
static void do_debug(const char *str, void *user_data)
|
||||||
@ -147,6 +153,87 @@ static void hwsim_config(struct l_genl_msg *msg, void *user_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void list_callback_done(void *user_data)
|
||||||
|
{
|
||||||
|
l_main_quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_callback(struct l_genl_msg *msg, void *user_data)
|
||||||
|
{
|
||||||
|
struct l_genl_attr attr;
|
||||||
|
uint16_t type, len;
|
||||||
|
const void *data;
|
||||||
|
uint32_t idx = 0, channels = 0, custom_reg = 0;
|
||||||
|
bool reg_strict = false, p2p = false, chanctx = false;
|
||||||
|
char alpha2[2] = { };
|
||||||
|
char *hwname = NULL;
|
||||||
|
|
||||||
|
if (!l_genl_attr_init(&attr, msg)) {
|
||||||
|
int err = l_genl_msg_get_error(msg);
|
||||||
|
if (err < 0) {
|
||||||
|
l_warn("Failed to list radio [%d/%s]",
|
||||||
|
-err, strerror(-err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (l_genl_attr_next(&attr, &type, &len, &data)) {
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case HWSIM_ATTR_RADIO_ID:
|
||||||
|
if (len == 4)
|
||||||
|
idx = *(int *)data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HWSIM_ATTR_CHANNELS:
|
||||||
|
if (len == 4)
|
||||||
|
channels = *(uint32_t *)data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HWSIM_ATTR_REG_HINT_ALPHA2:
|
||||||
|
if (len == 2)
|
||||||
|
memcpy(&alpha2, data, len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HWSIM_ATTR_REG_CUSTOM_REG:
|
||||||
|
if (len == 4)
|
||||||
|
custom_reg = *(uint32_t *)data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HWSIM_ATTR_REG_STRICT_REG:
|
||||||
|
reg_strict = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HWSIM_ATTR_SUPPORT_P2P_DEVICE:
|
||||||
|
p2p = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HWSIM_ATTR_USE_CHANCTX:
|
||||||
|
chanctx = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HWSIM_ATTR_RADIO_NAME:
|
||||||
|
hwname = l_malloc(len + 1);
|
||||||
|
if (hwname) {
|
||||||
|
strncpy(hwname, data, len);
|
||||||
|
hwname[len] = '\0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s radio id %d channels %d alpha2 %d %d custom reg %d "
|
||||||
|
"reg strict %d p2p %d chanctx %d\n",
|
||||||
|
hwname, idx, channels, alpha2[0], alpha2[1], custom_reg,
|
||||||
|
reg_strict, p2p, chanctx);
|
||||||
|
|
||||||
|
if (hwname)
|
||||||
|
l_free(hwname);
|
||||||
|
}
|
||||||
|
|
||||||
static void hwsim_ready(void *user_data)
|
static void hwsim_ready(void *user_data)
|
||||||
{
|
{
|
||||||
struct l_genl_msg *msg;
|
struct l_genl_msg *msg;
|
||||||
@ -178,6 +265,21 @@ static void hwsim_ready(void *user_data)
|
|||||||
msg = l_genl_msg_new_sized(HWSIM_CMD_DEL_RADIO, 8);
|
msg = l_genl_msg_new_sized(HWSIM_CMD_DEL_RADIO, 8);
|
||||||
l_genl_msg_append_attr(msg, HWSIM_ATTR_RADIO_ID, 4, &id);
|
l_genl_msg_append_attr(msg, HWSIM_ATTR_RADIO_ID, 4, &id);
|
||||||
l_genl_family_send(hwsim, msg, destroy_callback, NULL, NULL);
|
l_genl_family_send(hwsim, msg, destroy_callback, NULL, NULL);
|
||||||
|
l_genl_msg_unref(msg);
|
||||||
|
} else if (list_action) {
|
||||||
|
msg = l_genl_msg_new_sized(HWSIM_CMD_GET_RADIO,
|
||||||
|
list_option ? 8: 4);
|
||||||
|
if (list_option) {
|
||||||
|
uint32_t id = atoi(list_option);
|
||||||
|
l_genl_msg_append_attr(msg, HWSIM_ATTR_RADIO_ID,
|
||||||
|
4, &id);
|
||||||
|
l_genl_family_send(hwsim, msg, list_callback,
|
||||||
|
NULL, NULL);
|
||||||
|
} else {
|
||||||
|
l_genl_family_dump(hwsim, msg, list_callback,
|
||||||
|
NULL, list_callback_done);
|
||||||
|
}
|
||||||
|
|
||||||
l_genl_msg_unref(msg);
|
l_genl_msg_unref(msg);
|
||||||
} else
|
} else
|
||||||
l_main_quit();
|
l_main_quit();
|
||||||
@ -206,6 +308,7 @@ static void usage(void)
|
|||||||
"Usage:\n");
|
"Usage:\n");
|
||||||
printf("\thwsim [options]\n");
|
printf("\thwsim [options]\n");
|
||||||
printf("Options:\n"
|
printf("Options:\n"
|
||||||
|
"\t-L, --list [id] List simulated radios\n"
|
||||||
"\t-C, --create Create new simulated radio\n"
|
"\t-C, --create Create new simulated radio\n"
|
||||||
"\t-D, --destroy <id> Destroy existing radio\n"
|
"\t-D, --destroy <id> Destroy existing radio\n"
|
||||||
"\t-k, --keep Do not destroy radios when "
|
"\t-k, --keep Do not destroy radios when "
|
||||||
@ -214,6 +317,7 @@ static void usage(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct option main_options[] = {
|
static const struct option main_options[] = {
|
||||||
|
{ "list", optional_argument, NULL, 'L' },
|
||||||
{ "create", no_argument, NULL, 'C' },
|
{ "create", no_argument, NULL, 'C' },
|
||||||
{ "destroy", required_argument, NULL, 'D' },
|
{ "destroy", required_argument, NULL, 'D' },
|
||||||
{ "keep", no_argument, NULL, 'k' },
|
{ "keep", no_argument, NULL, 'k' },
|
||||||
@ -227,21 +331,37 @@ int main(int argc, char *argv[])
|
|||||||
struct l_signal *signal;
|
struct l_signal *signal;
|
||||||
struct l_genl *genl;
|
struct l_genl *genl;
|
||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
int exit_status;
|
int exit_status, actions = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
opt = getopt_long(argc, argv, "CD:vhk", main_options, NULL);
|
opt = getopt_long(argc, argv, ":L:CD:vhk", main_options, NULL);
|
||||||
if (opt < 0)
|
if (opt < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
case ':':
|
||||||
|
if (optopt == 'L') {
|
||||||
|
list_action = true;
|
||||||
|
actions++;
|
||||||
|
} else {
|
||||||
|
printf("option '-%c' requires an argument\n",
|
||||||
|
optopt);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
list_action = true;
|
||||||
|
list_option = optarg;
|
||||||
|
actions++;
|
||||||
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
create_action = true;
|
create_action = true;
|
||||||
|
actions++;
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
destroy_action = optarg;
|
destroy_action = optarg;
|
||||||
|
actions++;
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
keep_radios = true;
|
keep_radios = true;
|
||||||
@ -253,6 +373,8 @@ int main(int argc, char *argv[])
|
|||||||
usage();
|
usage();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
default:
|
default:
|
||||||
|
printf("unrecognized argument '%s'\n",
|
||||||
|
argv[optind - 1]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,12 +384,12 @@ int main(int argc, char *argv[])
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create_action && destroy_action) {
|
if (actions > 1) {
|
||||||
fprintf(stderr, "Only one action can be specified\n");
|
fprintf(stderr, "Only one action can be specified\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!create_action && !destroy_action) {
|
if (!actions) {
|
||||||
fprintf(stderr, "No action has been specified\n");
|
fprintf(stderr, "No action has been specified\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user