mirror of
https://github.com/szehl/ath9k-hmac.git
synced 2024-12-18 21:37:51 +00:00
HMAC user space daemon
This commit is contained in:
parent
d9d1d9cf3c
commit
9c1055cae6
6
hmac_userspace_daemon/Makefile
Normal file
6
hmac_userspace_daemon/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
all: hybrid_tdma_csma_mac_x86
|
||||
|
||||
hybrid_tdma_csma_mac_x86:
|
||||
g++ hybrid_tdma_csma_mac.c -I /usr/include/libnl3/ -DCONFIG_LIBNL30 -o hmac_userspace_daemon -levent -lnl-genl-3 -lnl-3 -lzmq -lstdc++ -lpthread
|
||||
clean:
|
||||
rm hmac_userspace_daemon
|
491
hmac_userspace_daemon/hybrid_tdma_csma_mac.c
Normal file
491
hmac_userspace_daemon/hybrid_tdma_csma_mac.c
Normal file
@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Userland part of the hybrid TDMA/CSMA MAC processor which is responsible for sending the configuration at
|
||||
* the beginning of each time slot to the ATH9k WiFi driver using Netlink.
|
||||
*
|
||||
* build with: make all
|
||||
*
|
||||
* @authors S Zehl, A. Zubow
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/queue.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#ifdef _EVENT_HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <event2/event.h>
|
||||
#include <event2/event_struct.h>
|
||||
#include <event2/util.h>
|
||||
#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 <stdbool.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 <netlink/socket.h>
|
||||
#include <stdlib.h>
|
||||
#include "../backports-3.12.8-1/include/uapi/linux/nl80211.h"
|
||||
#include "iw.h"
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <zmq.hpp>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
// struct to be passed via netlink to ath9k driver
|
||||
struct tid_sleep_tuple
|
||||
{
|
||||
char mac[6]; // destination MAC address
|
||||
char mask; // TID mask
|
||||
};
|
||||
|
||||
int mDebug = 0;
|
||||
|
||||
int isRunning = 1;
|
||||
|
||||
// Used by local controller for communication with mac processor
|
||||
int LOCAL_MAC_PROCESSOR_CTRL_PORT = 1217;
|
||||
|
||||
// variables set at start-up
|
||||
long slotDuration = 10000; // mus
|
||||
int slotsPerFrame = 10; // e.g. 10
|
||||
char * interface; // e.g. wifi0
|
||||
char * configuration; // e.g. 1,mac_addr,tid_map;2,mac_addr,tid_map
|
||||
|
||||
// updated at runtime
|
||||
std::string *schedule_per_slot = NULL;
|
||||
|
||||
struct nl80211_state state;
|
||||
|
||||
// internal state for keeping slotting time aligned
|
||||
long oldtime_l = 0;
|
||||
int event_is_persistent;
|
||||
const int estimatePrecisionEveryNslots = 1000;
|
||||
int times[estimatePrecisionEveryNslots];
|
||||
int cnt = 0;
|
||||
long gl_clock = 0; // global clock w/ step size of slotDuration
|
||||
long slotCnt = 0; // total slot counter
|
||||
long frameCnt = 0; // total frame counter
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** helper functions for string manipulation */
|
||||
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, delim)) {
|
||||
elems.push_back(item);
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
|
||||
/** helper functions for string manipulation */
|
||||
std::vector<std::string> split(const std::string &s, char delim) {
|
||||
std::vector<std::string> elems;
|
||||
split(s, delim, elems);
|
||||
return elems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at start-up or in case of reconfiguration.
|
||||
*/
|
||||
void updateSchedule(std::string &msg) {
|
||||
|
||||
// init
|
||||
for (int i=0; i<slotsPerFrame; i++) {
|
||||
schedule_per_slot[i] = "";
|
||||
}
|
||||
|
||||
// assign configuration to each slot
|
||||
std::vector<std::string> msg_parts = split(msg, '#');
|
||||
|
||||
for (int k=0; k<msg_parts.size(); k++) {
|
||||
std::vector<std::string> entry = split(msg_parts[k], ',');
|
||||
|
||||
int slot_id = atoi(entry[0].c_str());
|
||||
const char * mac_addr = entry[1].c_str();
|
||||
int tid_mask = atoi(entry[2].c_str());
|
||||
|
||||
std::stringstream ss;
|
||||
if (schedule_per_slot[slot_id].empty()) {
|
||||
ss << mac_addr << "," << entry[2].c_str();
|
||||
} else {
|
||||
ss << schedule_per_slot[slot_id] << "#" << mac_addr << "," << entry[2].c_str();
|
||||
}
|
||||
|
||||
schedule_per_slot[slot_id] = ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
/** Worker thread responsible for receiving new configuration updates */
|
||||
void *worker_routine (void *arg)
|
||||
{
|
||||
std::cout << "Worker routine started ... ready to receive new configuration messages via ZMQ socket." << std::endl;
|
||||
|
||||
zmq::context_t *context = (zmq::context_t *) arg;
|
||||
zmq::socket_t socket (*context, ZMQ_REP);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "tcp://*:" << LOCAL_MAC_PROCESSOR_CTRL_PORT;
|
||||
socket.bind (ss.str().c_str());
|
||||
//socket.bind ("ipc:///tmp/localmacprocessor");
|
||||
|
||||
while (true) {
|
||||
zmq::message_t request;
|
||||
|
||||
// Wait for next request from client
|
||||
socket.recv (&request);
|
||||
|
||||
std::string msg = std::string(static_cast<char*>(request.data()), request.size());
|
||||
std::cout << "Received new configuration update: " << msg << std::endl;
|
||||
|
||||
if (msg.find("TERMINATE") == 0) {
|
||||
// shutdown process
|
||||
isRunning = 0;
|
||||
} else {
|
||||
// update slot schedule
|
||||
updateSchedule(msg);
|
||||
}
|
||||
|
||||
sleep (0.1);
|
||||
|
||||
// Send ACK to client
|
||||
zmq::message_t reply(2);
|
||||
memcpy ((void *) reply.data(), "OK", 2);
|
||||
socket.send(reply);
|
||||
if(isRunning == 0)
|
||||
{
|
||||
socket.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** netlink error handling */
|
||||
static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
|
||||
void *arg)
|
||||
{
|
||||
int *ret = (int*) arg;
|
||||
*ret = err->error;
|
||||
|
||||
printf("->CFG80211 returns: error: No:%d, %s\n",err->error, strerror((-1)*err->error));
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
static int finish_handler(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
int *ret = (int*) arg;
|
||||
*ret = 0;
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
static int ack_handler(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
int *ret = (int*) arg;
|
||||
*ret = 0;
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
static int send_nl_msg(std::string& schedule)
|
||||
{
|
||||
if (mDebug == 1) {
|
||||
std::cout << "Send schedule via netlink to ath9k driver: " << schedule << std::endl;
|
||||
}
|
||||
|
||||
std::vector<std::string> tuples = split(schedule, '#');
|
||||
|
||||
struct nl_cb *cb;
|
||||
struct nl_cb *s_cb;
|
||||
struct nl_msg *msg;
|
||||
signed long long devidx = 0;
|
||||
int err = 0;
|
||||
devidx = if_nametoindex(interface);
|
||||
|
||||
msg = nlmsg_alloc();
|
||||
if (!msg) {
|
||||
fprintf(stderr, "failed to allocate netlink message\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
cb = nl_cb_alloc(NL_CB_DEFAULT);
|
||||
s_cb = nl_cb_alloc(NL_CB_DEFAULT);
|
||||
if (!cb || !s_cb) {
|
||||
fprintf(stderr, "failed to allocate netlink callbacks\n");
|
||||
err = 2;
|
||||
goto out_free_msg;
|
||||
}
|
||||
|
||||
// create NetLink message
|
||||
genlmsg_put(msg, 0, 0, state.nl80211_id, 0, 0, NL80211_ATTR_TID_SLEEP_CTRL, 0);
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
|
||||
|
||||
// update tids_tuple with current slot schedule
|
||||
uint8_t mac_u8[6];
|
||||
struct tid_sleep_tuple tids_tuple[tuples.size()];
|
||||
for (int k=0; k<tuples.size(); k++) {
|
||||
std::vector<std::string> tuple = split(tuples[k], ',');
|
||||
sscanf(tuple[0].c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac_u8[0], &mac_u8[1], &mac_u8[2], &mac_u8[3], &mac_u8[4], &mac_u8[5]);
|
||||
int tid_mask = atoi(tuple[1].c_str());
|
||||
|
||||
for (int zz=0; zz<6; zz++) {
|
||||
tids_tuple[k].mac[zz] = mac_u8[zz];
|
||||
}
|
||||
tids_tuple[k].mask = tid_mask;
|
||||
}
|
||||
|
||||
NLA_PUT(msg, NL80211_ATTR_TID_SLEEP_CTRL_DATA, sizeof(struct tid_sleep_tuple)*tuples.size(), (const void *) &tids_tuple[0]);
|
||||
nl_socket_set_cb(state.nl_sock, s_cb);
|
||||
|
||||
// send message
|
||||
err = nl_send_auto_complete(state.nl_sock, msg);
|
||||
if (err < 0)
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/** initialize netlink */
|
||||
static int nl80211_init(struct nl80211_state *state)
|
||||
{
|
||||
int err;
|
||||
|
||||
printf("nl80211 init called v2\n");
|
||||
|
||||
state->nl_sock = nl_socket_alloc();
|
||||
if (!state->nl_sock) {
|
||||
fprintf(stderr, "Failed to allocate netlink socket.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nl_socket_set_buffer_size(state->nl_sock, 8192, 8192);
|
||||
|
||||
if (genl_connect(state->nl_sock)) {
|
||||
fprintf(stderr, "Failed to connect to generic netlink.\n");
|
||||
err = -ENOLINK;
|
||||
goto out_handle_destroy;
|
||||
}
|
||||
|
||||
state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
|
||||
if (state->nl80211_id < 0) {
|
||||
fprintf(stderr, "nl80211 not found.\n");
|
||||
err = -ENOENT;
|
||||
goto out_handle_destroy;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_handle_destroy:
|
||||
nl_socket_free(state->nl_sock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/** timer callback called at the beginning of each new slot */
|
||||
static void
|
||||
timeout_cb(evutil_socket_t fd, short event, void *arg)
|
||||
{
|
||||
struct timeval newtime, difference;
|
||||
struct event *timeout = (struct event *)arg;
|
||||
long error = 0;
|
||||
|
||||
if (isRunning == 0) {
|
||||
printf("Terminating ...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
evutil_gettimeofday(&newtime, NULL);
|
||||
long newtime_l = 1000000 * newtime.tv_sec + newtime.tv_usec;
|
||||
|
||||
if (gl_clock == 0) {
|
||||
gl_clock = (newtime_l / slotDuration) * slotDuration;
|
||||
slotCnt = 0;
|
||||
frameCnt = 0;
|
||||
} else {
|
||||
gl_clock = gl_clock + (slotDuration % 1000000);
|
||||
slotCnt++;
|
||||
frameCnt = slotCnt / slotsPerFrame;
|
||||
}
|
||||
// current frame number
|
||||
long relFrameNum = slotCnt % slotsPerFrame;
|
||||
|
||||
// estimate slot scheduling precision
|
||||
if(cnt < estimatePrecisionEveryNslots) {
|
||||
times[cnt] = newtime_l;
|
||||
cnt++;
|
||||
} else if(cnt == estimatePrecisionEveryNslots) {
|
||||
double sum = 0;
|
||||
for(int i = 1; i < estimatePrecisionEveryNslots; i++) {
|
||||
sum += times[i] - times[i-1];
|
||||
}
|
||||
sum = sum / (estimatePrecisionEveryNslots-1);
|
||||
|
||||
printf("Average slot duration: %.2f\n", sum);
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
if (!event_is_persistent) {
|
||||
struct timeval tv;
|
||||
evutil_timerclear(&tv);
|
||||
|
||||
if (oldtime_l != 0) {
|
||||
error = 2 * (newtime_l - gl_clock);
|
||||
}
|
||||
|
||||
tv.tv_sec = slotDuration / 1000000;
|
||||
tv.tv_usec = (slotDuration % 1000000) - error;
|
||||
|
||||
event_add(timeout, &tv);
|
||||
oldtime_l = newtime_l;
|
||||
|
||||
send_nl_msg(schedule_per_slot[relFrameNum]);
|
||||
}
|
||||
}
|
||||
|
||||
/** main entry point */
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct event timeout;
|
||||
struct timeval tv;
|
||||
struct event_base *base;
|
||||
int flags;
|
||||
int err;
|
||||
char * inter_ptr;
|
||||
char * conf_ptr;
|
||||
int opt = 0;
|
||||
char *mac = NULL;
|
||||
char *guard_frames = NULL;
|
||||
char *best_effort = NULL;
|
||||
char *voice = NULL;
|
||||
char *pt;
|
||||
interface = '\0';
|
||||
configuration = '\0';
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:i:f:n:c:")) != -1) {
|
||||
switch(opt) {
|
||||
case 'd':
|
||||
mDebug = atoi(optarg);
|
||||
printf("\nDebug = %d", mDebug);
|
||||
break;
|
||||
case 'i':
|
||||
inter_ptr = optarg;
|
||||
interface = (char *) malloc(strlen(inter_ptr));
|
||||
strcpy(interface, inter_ptr);
|
||||
printf("\nInterface = %s", interface);
|
||||
break;
|
||||
case 'f':
|
||||
slotDuration = atoi(optarg);
|
||||
printf("\nSlot Duration = %lu", slotDuration);
|
||||
break;
|
||||
case 'n':
|
||||
slotsPerFrame = atoi(optarg);
|
||||
printf("\nTotal number of slots in frame = %d", slotsPerFrame);
|
||||
break;
|
||||
case 'c':
|
||||
conf_ptr = optarg;
|
||||
configuration = (char *) malloc(strlen(conf_ptr));
|
||||
strcpy(configuration, conf_ptr);
|
||||
printf("\nConfig = %s", configuration);
|
||||
break;
|
||||
case '?':
|
||||
printf("Usage: ./hybrid_tdma_csma_mac -i wifi0 -f 20000 -n 10\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// init schedule
|
||||
schedule_per_slot = new std::string[slotsPerFrame];
|
||||
|
||||
// update schedule
|
||||
std::string msg(configuration);
|
||||
updateSchedule(msg);
|
||||
|
||||
if (interface == NULL) {
|
||||
printf("Error no interface supplied. Usage: ./hybrid_tdma_csma_mac -i wifi0 -f 20000 -n 10\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Using init schedule w/:\n");
|
||||
|
||||
for(int i=0; i<10; i++) {
|
||||
printf("#%d: %s, ", i, schedule_per_slot[i].c_str());
|
||||
}
|
||||
|
||||
// Prepare our context and sockets
|
||||
zmq::context_t context (1);
|
||||
|
||||
try {
|
||||
pthread_t worker;
|
||||
pthread_create (&worker, NULL, worker_routine, (void *) &context);
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Error setting up ZMQ: " << ex.what() << std::endl;
|
||||
return -1;
|
||||
} catch (...) {
|
||||
std::cerr << "Other strange error!!! " << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = nl80211_init(&state);
|
||||
|
||||
event_is_persistent = 0;
|
||||
flags = 0;
|
||||
|
||||
/* Initalize the event library */
|
||||
base = event_base_new();
|
||||
|
||||
/* Initalize one event */
|
||||
event_assign(&timeout, base, -1, flags, timeout_cb, (void*) &timeout);
|
||||
|
||||
evutil_timerclear(&tv);
|
||||
|
||||
/* align schedule to seconds */
|
||||
struct timeval curTime;
|
||||
evutil_gettimeofday(&curTime, NULL);
|
||||
|
||||
int mus = 1000000 - curTime.tv_usec;
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = mus;
|
||||
event_add(&timeout, &tv);
|
||||
|
||||
event_base_dispatch(base);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
61
hmac_userspace_daemon/ieee80211.h
Normal file
61
hmac_userspace_daemon/ieee80211.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef __IEEE80211
|
||||
#define __IEEE80211
|
||||
|
||||
/* 802.11n HT capability AMPDU settings (for ampdu_params_info) */
|
||||
#define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03
|
||||
#define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C
|
||||
|
||||
#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002
|
||||
#define IEEE80211_HT_CAP_SGI_40 0x0040
|
||||
#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800
|
||||
|
||||
#define IEEE80211_HT_MCS_MASK_LEN 10
|
||||
|
||||
/**
|
||||
* struct ieee80211_mcs_info - MCS information
|
||||
* @rx_mask: RX mask
|
||||
* @rx_highest: highest supported RX rate. If set represents
|
||||
* the highest supported RX data rate in units of 1 Mbps.
|
||||
* If this field is 0 this value should not be used to
|
||||
* consider the highest RX data rate supported.
|
||||
* @tx_params: TX parameters
|
||||
*/
|
||||
struct ieee80211_mcs_info {
|
||||
__u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN];
|
||||
__u16 rx_highest;
|
||||
__u8 tx_params;
|
||||
__u8 reserved[3];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/**
|
||||
* struct ieee80211_ht_cap - HT capabilities
|
||||
*
|
||||
* This structure is the "HT capabilities element" as
|
||||
* described in 802.11n D5.0 7.3.2.57
|
||||
*/
|
||||
struct ieee80211_ht_cap {
|
||||
__u16 cap_info;
|
||||
__u8 ampdu_params_info;
|
||||
|
||||
/* 16 bytes MCS information */
|
||||
struct ieee80211_mcs_info mcs;
|
||||
|
||||
__u16 extended_ht_cap_info;
|
||||
__u32 tx_BF_cap_info;
|
||||
__u8 antenna_selection_info;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_vht_mcs_info {
|
||||
__u16 rx_vht_mcs;
|
||||
__u16 rx_highest;
|
||||
__u16 tx_vht_mcs;
|
||||
__u16 tx_highest;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_vht_cap {
|
||||
__u32 cap_info;
|
||||
struct ieee80211_vht_mcs_info mcs;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* __IEEE80211 */
|
177
hmac_userspace_daemon/iw.h
Normal file
177
hmac_userspace_daemon/iw.h
Normal file
@ -0,0 +1,177 @@
|
||||
#ifndef __IW_H
|
||||
#define __IW_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/genl/genl.h>
|
||||
#include <netlink/genl/family.h>
|
||||
#include <netlink/genl/ctrl.h>
|
||||
#include <endian.h>
|
||||
|
||||
#include "ieee80211.h"
|
||||
|
||||
#define ETH_ALEN 6
|
||||
|
||||
/* libnl 1.x compatibility code */
|
||||
#if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30)
|
||||
# define nl_sock nl_handle
|
||||
#endif
|
||||
|
||||
struct nl80211_state {
|
||||
struct nl_sock *nl_sock;
|
||||
int nl80211_id;
|
||||
};
|
||||
|
||||
enum command_identify_by {
|
||||
CIB_NONE,
|
||||
CIB_PHY,
|
||||
CIB_NETDEV,
|
||||
CIB_WDEV,
|
||||
};
|
||||
|
||||
enum id_input {
|
||||
II_NONE,
|
||||
II_NETDEV,
|
||||
II_PHY_NAME,
|
||||
II_PHY_IDX,
|
||||
II_WDEV,
|
||||
};
|
||||
|
||||
struct cmd {
|
||||
const char *name;
|
||||
const char *args;
|
||||
const char *help;
|
||||
const enum nl80211_commands cmd;
|
||||
int nl_msg_flags;
|
||||
int hidden;
|
||||
const enum command_identify_by idby;
|
||||
/*
|
||||
* The handler should return a negative error code,
|
||||
* zero on success, 1 if the arguments were wrong
|
||||
* and the usage message should and 2 otherwise.
|
||||
*/
|
||||
int (*handler)(struct nl80211_state *state,
|
||||
struct nl_cb *cb,
|
||||
struct nl_msg *msg,
|
||||
int argc, char **argv,
|
||||
enum id_input id);
|
||||
const struct cmd *(*selector)(int argc, char **argv);
|
||||
const struct cmd *parent;
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0]))
|
||||
#define DIV_ROUND_UP(x, y) (((x) + (y - 1)) / (y))
|
||||
|
||||
#define __COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel)\
|
||||
static struct cmd \
|
||||
__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden\
|
||||
__attribute__((used)) __attribute__((section("__cmd"))) = { \
|
||||
.name = (_name), \
|
||||
.args = (_args), \
|
||||
.cmd = (_nlcmd), \
|
||||
.nl_msg_flags = (_flags), \
|
||||
.hidden = (_hidden), \
|
||||
.idby = (_idby), \
|
||||
.handler = (_handler), \
|
||||
.help = (_help), \
|
||||
.parent = _section, \
|
||||
.selector = (_sel), \
|
||||
}
|
||||
#define __ACMD(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel, _alias)\
|
||||
__COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel);\
|
||||
static const struct cmd *_alias = &__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden
|
||||
#define COMMAND(section, name, args, cmd, flags, idby, handler, help) \
|
||||
__COMMAND(&(__section ## _ ## section), name, #name, args, cmd, flags, 0, idby, handler, help, NULL)
|
||||
#define COMMAND_ALIAS(section, name, args, cmd, flags, idby, handler, help, selector, alias)\
|
||||
__ACMD(&(__section ## _ ## section), name, #name, args, cmd, flags, 0, idby, handler, help, selector, alias)
|
||||
#define HIDDEN(section, name, args, cmd, flags, idby, handler) \
|
||||
__COMMAND(&(__section ## _ ## section), name, #name, args, cmd, flags, 1, idby, handler, NULL, NULL)
|
||||
|
||||
#define TOPLEVEL(_name, _args, _nlcmd, _flags, _idby, _handler, _help) \
|
||||
struct cmd \
|
||||
__section ## _ ## _name \
|
||||
__attribute__((used)) __attribute__((section("__cmd"))) = { \
|
||||
.name = (#_name), \
|
||||
.args = (_args), \
|
||||
.cmd = (_nlcmd), \
|
||||
.nl_msg_flags = (_flags), \
|
||||
.idby = (_idby), \
|
||||
.handler = (_handler), \
|
||||
.help = (_help), \
|
||||
}
|
||||
#define SECTION(_name) \
|
||||
struct cmd __section ## _ ## _name \
|
||||
__attribute__((used)) __attribute__((section("__cmd"))) = { \
|
||||
.name = (#_name), \
|
||||
.hidden = 1, \
|
||||
}
|
||||
|
||||
#define DECLARE_SECTION(_name) \
|
||||
extern struct cmd __section ## _ ## _name;
|
||||
|
||||
extern const char iw_version[];
|
||||
|
||||
extern int iw_debug;
|
||||
|
||||
int handle_cmd(struct nl80211_state *state, enum id_input idby,
|
||||
int argc, char **argv);
|
||||
|
||||
struct print_event_args {
|
||||
struct timeval ts; /* internal */
|
||||
bool have_ts; /* must be set false */
|
||||
bool frame, time, reltime;
|
||||
};
|
||||
|
||||
__u32 listen_events(struct nl80211_state *state,
|
||||
const int n_waits, const __u32 *waits);
|
||||
int __prepare_listen_events(struct nl80211_state *state);
|
||||
__u32 __do_listen_events(struct nl80211_state *state,
|
||||
const int n_waits, const __u32 *waits,
|
||||
struct print_event_args *args);
|
||||
|
||||
|
||||
int mac_addr_a2n(unsigned char *mac_addr, char *arg);
|
||||
void mac_addr_n2a(char *mac_addr, unsigned char *arg);
|
||||
int parse_hex_mask(char *hexmask, unsigned char **result, size_t *result_len,
|
||||
unsigned char **mask);
|
||||
unsigned char *parse_hex(char *hex, size_t *outlen);
|
||||
|
||||
int parse_keys(struct nl_msg *msg, char **argv, int argc);
|
||||
|
||||
void print_ht_mcs(const __u8 *mcs);
|
||||
void print_ampdu_length(__u8 exponent);
|
||||
void print_ampdu_spacing(__u8 spacing);
|
||||
void print_ht_capability(__u16 cap);
|
||||
void print_vht_info(__u32 capa, const __u8 *mcs);
|
||||
|
||||
char *channel_width_name(enum nl80211_chan_width width);
|
||||
const char *iftype_name(enum nl80211_iftype iftype);
|
||||
const char *command_name(enum nl80211_commands cmd);
|
||||
int ieee80211_channel_to_frequency(int chan, enum nl80211_band band);
|
||||
int ieee80211_frequency_to_channel(int freq);
|
||||
|
||||
void print_ssid_escaped(const uint8_t len, const uint8_t *data);
|
||||
|
||||
int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group);
|
||||
|
||||
char *reg_initiator_to_string(__u8 initiator);
|
||||
|
||||
const char *get_reason_str(uint16_t reason);
|
||||
const char *get_status_str(uint16_t status);
|
||||
|
||||
enum print_ie_type {
|
||||
PRINT_SCAN,
|
||||
PRINT_LINK,
|
||||
};
|
||||
|
||||
#define BIT(x) (1ULL<<(x))
|
||||
|
||||
void print_ies(unsigned char *ie, int ielen, bool unknown,
|
||||
enum print_ie_type ptype);
|
||||
|
||||
void parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen);
|
||||
|
||||
DECLARE_SECTION(set);
|
||||
DECLARE_SECTION(get);
|
||||
|
||||
#endif /* __IW_H */
|
Loading…
Reference in New Issue
Block a user