android13/hardware/bes/wireless/besphy_rf_cmd/besphy_rf.c

401 lines
10 KiB
C
Executable File

/*
* nl80211 test tool
*
* Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
#include "nl80211.h"
#include "besphy_rf.h"
#if (!defined CONFIG_LIBNL20) && (!defined CONFIG_LIBNL30)
/* libnl 2.0 && libnl 3.0 compatibility code */
static inline struct nl_handle *nl_socket_alloc(void)
{
return nl_handle_alloc();
}
static inline void nl_socket_free(struct nl_sock *h)
{
nl_handle_destroy(h);
}
static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, struct nl_cache **cache)
{
struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
if (!tmp)
return -ENOMEM;
*cache = tmp;
return 0;
}
#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
#endif /* CONFIG_LIBNL20 && CONFIG_LIBNL30*/
static int nl80211_init(struct nl80211_state *state)
{
int err;
state->nl_sock = nl_socket_alloc();
if (!state->nl_sock) {
fprintf(stderr, "Failed to allocate netlink socket.\n");
return -ENOMEM;
}
if (genl_connect(state->nl_sock)) {
fprintf(stderr, "Failed to connect to generic netlink.\n");
err = -ENOLINK;
goto out_handle_destroy;
}
if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) {
fprintf(stderr, "Failed to allocate generic netlink cache.\n");
err = -ENOMEM;
goto out_handle_destroy;
}
state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
if (!state->nl80211) {
fprintf(stderr, "nl80211 not found.\n");
err = -ENOENT;
goto out_cache_free;
}
/*
* Enable peek mode so drivers can send large amounts
* of data in blobs without problems.
*/
nl_socket_enable_msg_peek(state->nl_sock);
return 0;
out_cache_free:
nl_cache_free(state->nl_cache);
out_handle_destroy:
nl_socket_free(state->nl_sock);
return err;
}
static void nl80211_cleanup(struct nl80211_state *state)
{
genl_family_put(state->nl80211);
nl_cache_free(state->nl_cache);
nl_socket_free(state->nl_sock);
}
static int phy_lookup(char *name)
{
char buf[200];
int fd, pos;
snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
fd = open(buf, O_RDONLY);
if (fd < 0)
return -1;
pos = read(fd, buf, sizeof(buf) - 1);
if (pos < 0)
return -1;
buf[pos] = '\0';
return atoi(buf);
}
static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
void *arg)
{
int *ret = arg;
*ret = err->error;
printf("error handler NL_STOP = %d\n", NL_STOP);
return NL_STOP;
}
static int finish_handler(struct nl_msg *msg, void *arg)
{
int *ret = arg;
printf("finish handler NL_SKIP = %d\n", NL_SKIP);
*ret = 0;
return NL_SKIP;
}
static int ack_handler(struct nl_msg *msg, void *arg)
{
int *ret = arg;
printf("ack handler NL_STOP = %d\n", NL_STOP);
*ret = 0;
return NL_STOP;
}
static char wlan0_vector[6] = {'w','l','a','n','0','\0'};
static void wlan_add(int argc, char **argv)
{
int i;
char *tmp[argc + 1];
tmp[0] = wlan0_vector;
char **argv_tmp = argv;
for (i = 1; i <= argc; i++) {
tmp[i] = *argv_tmp++;
}
for (i = 0; i <= argc; i++) {
*argv++ = tmp[i];
}
}
static int handle(struct nl80211_state *state, int argc, char **argv)
{
struct nl_cb *cb;
struct nl_msg *msg;
struct nlattr *nest;
int devidx = 0;
int err;
if (!argc) {
printf("no dev/phy given\n");
return 1;
}
/* CHANGE HERE: you may need to allocate larger messages! */
msg = nlmsg_alloc();
if (!msg) {
fprintf(stderr, "failed to allocate netlink message\n");
return 2;
}
cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb) {
fprintf(stderr, "failed to allocate netlink callbacks\n");
err = 2;
goto out_free_msg;
}
genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0, NL80211_CMD_TESTMODE, 0);
//genlmsg_put(msg, 0, 0, state->nl80211, 0, 0, NL80211_CMD_TESTMODE, 0);
//genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
// 0, NL80211_CMD_TRIGGER_SCAN, 0);
devidx = if_nametoindex(*argv);
printf("dev = %s, devidx=%d\n", *argv, devidx);
if (devidx) {
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
} else {
devidx = phy_lookup(*argv);
if (devidx < 0) {
printf("Device not found\nCheck phyname/wlanname\n");
return 1;
}
printf("phy lookup index=%d\n", devidx);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
}
nest = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
if (!nest)
return 4;
err = do_commands(cb, msg, argc, argv);
nla_nest_end(msg, nest);
if (err) {
printf("do command error = %d\n", err);
goto out;
}
err = nl_send_auto_complete(state->nl_sock, msg);
if (err < 0) {
printf("nl_send_auto_complete err = %d\n", err);
goto out;
}
err = 1;
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
while (err > 0) {
//printf("while err = %d\n", err);
nl_recvmsgs(state->nl_sock, cb);
}
out:
nl_cb_put(cb);
out_free_msg:
nlmsg_free(msg);
return err;
nla_put_failure:
fprintf(stderr, "building message failed\n");
return 2;
}
static struct nl80211_state nl_state;
static struct nl_cb *cb_event = NULL;
static void besphy_remove(void)
{
if (cb_event)
nl_cb_put(cb_event);
nl80211_cleanup(&nl_state);
}
/**
* force exit program when event listening.
* receive the CTRL C forced exit signal, and then exit the program.
*/
void signal_handler(int signum)
{
besphy_remove();
printf("\n");
exit(signum);
}
void usage(void)
{
printf("besphy usage:\n"
"RF nosignaling commands:\n"
"\tbesphy [wlanname/phyname] start\n"
"\tbesphy [wlanname/phyname] bandwidth <value(20/40)>\n"
"\tbesphy [wlanname/phyname] rate <value>\n"
"\tbesphy [wlanname/phyname] get_rate\n"
"\tbesphy [wlanname/phyname] tx\n"
"\tbesphy [wlanname/phyname] tx_stop\n"
"\tbesphy [wlanname/phyname] rx\n"
"\tbesphy [wlanname/phyname] rx_ackSet\n"
"\tbesphy [wlanname/phyname] rx_ackRead\n"
"\tbesphy [wlanname/phyname] rx_stop\n"
"\tbesphy [wlanname/phyname] channel <value>\n"
"\tbesphy [wlanname/phyname] get_channel\n"
"\tbesphy [wlanname/phyname] powerlevel <value(hex)>\n"
"\tbesphy [wlanname/phyname] get_powerlevel\n"
"\tbesphy [wlanname/phyname] save_powerlevel\n"
"\tbesphy [wlanname/phyname] get_save_powerlevel\n"
"\tbesphy [wlanname/phyname] freqOffset <value(hex)>\n"
"\tbesphy [wlanname/phyname] get_freqOffset\n"
"\tbesphy [wlanname/phyname] save_freqoffset\n"
"\tbesphy [wlanname/phyname] get_save_freqoffset\n"
"\tbesphy [wlanname/phyname] save\n"
"\tbesphy [wlanname/phyname] wifi_stop\n"
"Help commands:\n"
"\tbesphy\n"
"\tbesphy -h\n"
"\tbesphy help\n"
"\nBy default, wlan0 is supported. When the device is not wlan0, "
"enter phyname/wlanname.\n\n");
}
static enum ARGV_PARSE_ATTR argc_parse(int argc, char **argv)
{
/* enter at least one command.(phyname/wlanname and one cmd) */
if (argc < 2)
return INVLID_ARGC;
argc--;
argv++;
enum ARGV_PARSE_ATTR ret = INVLID_ARGC;
if (argc == 1 && (!strcmp(argv[0], "-h") || !strcmp(argv[0], "help"))) {
ret = BESPHY_USAGE;
} else if (!strcmp(argv[0], "monitor") && argc == 1) {
ret = BESPHY_MONITOR;
} else {
ret = BESPHY_TESTMODE;
}
return ret;
}
int main(int argc, char **argv)
{
int err;
enum ARGV_PARSE_ATTR cmd_type;
/* strip off self */
argc--;
argv++;
if (argc == 0) {
usage();
return 0;
}
/* if phy* or wlan* is not inputed, add phy0 as the default parameter. */
if (!(!strncmp(*argv,"phy", 3) || !strncmp(*argv,"wlan", 4))) {
wlan_add(argc, argv);
argc++;
}
cmd_type = argc_parse(argc, argv);
if (cmd_type == BESPHY_USAGE) {
usage();
return 0;
}
err = nl80211_init(&nl_state);
if (err)
return 1;
switch (cmd_type) {
case BESPHY_USAGE:
err = 0;
break;
case BESPHY_TESTMODE:
err = handle(&nl_state, argc, argv);
if (err > 0)
printf("error!\n");
else if (err < 0)
printf("error: %d (%s)\n", err, strerror(-err));
if (err == -EINVAL)
printf("besphy: bad parameters (see \"besphy -h\")\n");
/**
* If need to monitor the event after sending the test command,
* enter the monitoring immediately.
* If not listening, exit the program.
*/
if (err == 0 && !strcmp(argv[1], "set_snap_frame"))
printf("start snap format frame listening...\n");
else
break;
case BESPHY_MONITOR:
err = prepare_listen_events(&nl_state, &cb_event);
if (err) {
printf("join multicast group failed, err: %d\n", err);
break;
}
printf("listen testmode event start...\n");
/* Initialize signal exit function. */
signal(SIGINT, signal_handler);
listen_events(&nl_state, cb_event);
break;
case INVLID_ARGC:
default:
printf("besphy: bad parameters (see \"besphy -h\")\n");
err = 1;
break;
}
besphy_remove();
return err;
}