mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2025-01-29 08:14:02 -05:00
hostapd: Add survey dump support
This adds survey dump support for all frequencies and for specific desired frequencies. This will later be used by ACS code for spectrum heuristics. Signed-hostap: Michal Kazior <michal.kazior@tieto.com>
This commit is contained in:
parent
245e026ec8
commit
0185007c2e
@ -225,4 +225,14 @@ static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
|
|||||||
hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
|
hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int hostapd_drv_get_survey(struct hostapd_data *hapd,
|
||||||
|
unsigned int freq)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL)
|
||||||
|
return -1;
|
||||||
|
if (!hapd->driver->get_survey)
|
||||||
|
return -1;
|
||||||
|
return hapd->driver->get_survey(hapd->drv_priv, freq);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* AP_DRV_OPS */
|
#endif /* AP_DRV_OPS */
|
||||||
|
@ -715,6 +715,72 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct hostapd_channel_data * hostapd_get_mode_channel(
|
||||||
|
struct hostapd_iface *iface, unsigned int freq)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct hostapd_channel_data *chan;
|
||||||
|
|
||||||
|
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||||
|
chan = &iface->current_mode->channels[i];
|
||||||
|
if (!chan)
|
||||||
|
return NULL;
|
||||||
|
if ((unsigned int) chan->freq == freq)
|
||||||
|
return chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_update_nf(struct hostapd_iface *iface,
|
||||||
|
struct hostapd_channel_data *chan,
|
||||||
|
struct freq_survey *survey)
|
||||||
|
{
|
||||||
|
if (!iface->chans_surveyed) {
|
||||||
|
chan->min_nf = survey->nf;
|
||||||
|
iface->lowest_nf = survey->nf;
|
||||||
|
} else {
|
||||||
|
if (dl_list_empty(&chan->survey_list))
|
||||||
|
chan->min_nf = survey->nf;
|
||||||
|
else if (survey->nf < chan->min_nf)
|
||||||
|
chan->min_nf = survey->nf;
|
||||||
|
if (survey->nf < iface->lowest_nf)
|
||||||
|
iface->lowest_nf = survey->nf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_event_get_survey(struct hostapd_data *hapd,
|
||||||
|
struct survey_results *survey_results)
|
||||||
|
{
|
||||||
|
struct hostapd_iface *iface = hapd->iface;
|
||||||
|
struct freq_survey *survey, *tmp;
|
||||||
|
struct hostapd_channel_data *chan;
|
||||||
|
|
||||||
|
if (dl_list_empty(&survey_results->survey_list)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "No survey data received");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
|
||||||
|
struct freq_survey, list) {
|
||||||
|
chan = hostapd_get_mode_channel(iface, survey->freq);
|
||||||
|
if (!chan)
|
||||||
|
continue;
|
||||||
|
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dl_list_del(&survey->list);
|
||||||
|
dl_list_add_tail(&chan->survey_list, &survey->list);
|
||||||
|
|
||||||
|
hostapd_update_nf(iface, chan, survey);
|
||||||
|
|
||||||
|
iface->chans_surveyed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
union wpa_event_data *data)
|
union wpa_event_data *data)
|
||||||
{
|
{
|
||||||
@ -856,6 +922,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
|||||||
hapd, data->connect_failed_reason.addr,
|
hapd, data->connect_failed_reason.addr,
|
||||||
data->connect_failed_reason.code);
|
data->connect_failed_reason.code);
|
||||||
break;
|
break;
|
||||||
|
case EVENT_SURVEY:
|
||||||
|
hostapd_event_get_survey(hapd, &data->survey_results);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
|
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
|
||||||
break;
|
break;
|
||||||
|
@ -301,6 +301,15 @@ struct hostapd_iface {
|
|||||||
int olbc_ht;
|
int olbc_ht;
|
||||||
|
|
||||||
u16 ht_op_mode;
|
u16 ht_op_mode;
|
||||||
|
|
||||||
|
/* surveying helpers */
|
||||||
|
|
||||||
|
/* number of channels surveyed */
|
||||||
|
unsigned int chans_surveyed;
|
||||||
|
|
||||||
|
/* lowest observed noise floor in dBm */
|
||||||
|
s8 lowest_nf;
|
||||||
|
|
||||||
void (*scan_cb)(struct hostapd_iface *iface);
|
void (*scan_cb)(struct hostapd_iface *iface);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define WPA_SUPPLICANT_DRIVER_VERSION 4
|
#define WPA_SUPPLICANT_DRIVER_VERSION 4
|
||||||
|
|
||||||
#include "common/defs.h"
|
#include "common/defs.h"
|
||||||
|
#include "utils/list.h"
|
||||||
|
|
||||||
#define HOSTAPD_CHAN_DISABLED 0x00000001
|
#define HOSTAPD_CHAN_DISABLED 0x00000001
|
||||||
#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
|
#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
|
||||||
@ -55,9 +56,20 @@ struct hostapd_channel_data {
|
|||||||
int flag;
|
int flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* max_tx_power - maximum transmit power in dBm
|
* max_tx_power - Maximum transmit power in dBm
|
||||||
*/
|
*/
|
||||||
u8 max_tx_power;
|
u8 max_tx_power;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* survey_list - Linked list of surveys
|
||||||
|
*/
|
||||||
|
struct dl_list survey_list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* min_nf - Minimum observed noise floor, in dBm, based on all
|
||||||
|
* surveyed channel data
|
||||||
|
*/
|
||||||
|
s8 min_nf;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
|
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
|
||||||
@ -2728,6 +2740,31 @@ struct wpa_driver_ops {
|
|||||||
* mode.
|
* mode.
|
||||||
*/
|
*/
|
||||||
int (*stop_ap)(void *priv);
|
int (*stop_ap)(void *priv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get_survey - Retrieve survey data
|
||||||
|
* @priv: Private driver interface data
|
||||||
|
* @freq: If set, survey data for the specified frequency is only
|
||||||
|
* being requested. If not set, all survey data is requested.
|
||||||
|
* Returns: 0 on success, -1 on failure
|
||||||
|
*
|
||||||
|
* Use this to retrieve:
|
||||||
|
*
|
||||||
|
* - the observed channel noise floor
|
||||||
|
* - the amount of time we have spent on the channel
|
||||||
|
* - the amount of time during which we have spent on the channel that
|
||||||
|
* the radio has determined the medium is busy and we cannot
|
||||||
|
* transmit
|
||||||
|
* - the amount of time we have spent receiving data
|
||||||
|
* - the amount of time we have spent transmitting data
|
||||||
|
*
|
||||||
|
* This data can be used for spectrum heuristics. One example is
|
||||||
|
* Automatic Channel Selection (ACS). The channel survey data is
|
||||||
|
* kept on a linked list on the channel data, one entry is added
|
||||||
|
* for each survey. The min_nf of the channel is updated for each
|
||||||
|
* survey.
|
||||||
|
*/
|
||||||
|
int (*get_survey)(void *priv, unsigned int freq);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -3212,10 +3249,56 @@ enum wpa_event_type {
|
|||||||
*
|
*
|
||||||
* The channel which was previously unavailable is now available again.
|
* The channel which was previously unavailable is now available again.
|
||||||
*/
|
*/
|
||||||
EVENT_DFS_NOP_FINISHED
|
EVENT_DFS_NOP_FINISHED,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EVENT_SURVEY - Received survey data
|
||||||
|
*
|
||||||
|
* This event gets triggered when a driver query is issued for survey
|
||||||
|
* data and the requested data becomes available. The returned data is
|
||||||
|
* stored in struct survey_results. The results provide at most one
|
||||||
|
* survey entry for each frequency and at minimum will provide one survey
|
||||||
|
* entry for one frequency. The survey data can be os_malloc()'d and
|
||||||
|
* then os_free()'d, so the event callback must only copy data.
|
||||||
|
*/
|
||||||
|
EVENT_SURVEY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct freq_survey - Channel survey info
|
||||||
|
*
|
||||||
|
* @ifidx: Interface index in which this survey was observed
|
||||||
|
* @freq: Center of frequency of the surveyed channel
|
||||||
|
* @nf: Channel noise floor in dBm
|
||||||
|
* @channel_time: Amount of time in ms the radio spent on the channel
|
||||||
|
* @channel_time_busy: Amount of time in ms the radio detected some signal
|
||||||
|
* that indicated to the radio the channel was not clear
|
||||||
|
* @channel_time_rx: Amount of time the radio spent receiving data
|
||||||
|
* @channel_time_tx: Amount of time the radio spent transmitting data
|
||||||
|
* @filled: bitmask indicating which fields have been reported, see
|
||||||
|
* SURVEY_HAS_* defines.
|
||||||
|
* @list: Internal list pointers
|
||||||
|
*/
|
||||||
|
struct freq_survey {
|
||||||
|
u32 ifidx;
|
||||||
|
unsigned int freq;
|
||||||
|
s8 nf;
|
||||||
|
u64 channel_time;
|
||||||
|
u64 channel_time_busy;
|
||||||
|
u64 channel_time_rx;
|
||||||
|
u64 channel_time_tx;
|
||||||
|
unsigned int filled;
|
||||||
|
struct dl_list list;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SURVEY_HAS_NF BIT(0)
|
||||||
|
#define SURVEY_HAS_CHAN_TIME BIT(1)
|
||||||
|
#define SURVEY_HAS_CHAN_TIME_BUSY BIT(2)
|
||||||
|
#define SURVEY_HAS_CHAN_TIME_RX BIT(3)
|
||||||
|
#define SURVEY_HAS_CHAN_TIME_TX BIT(4)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* union wpa_event_data - Additional data for wpa_supplicant_event() calls
|
* union wpa_event_data - Additional data for wpa_supplicant_event() calls
|
||||||
*/
|
*/
|
||||||
@ -3858,6 +3941,17 @@ union wpa_event_data {
|
|||||||
struct dfs_event {
|
struct dfs_event {
|
||||||
int freq;
|
int freq;
|
||||||
} dfs_event;
|
} dfs_event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* survey_results - Survey result data for EVENT_SURVEY
|
||||||
|
* @freq_filter: Requested frequency survey filter, 0 if request
|
||||||
|
* was for all survey data
|
||||||
|
* @survey_list: Linked list of survey data
|
||||||
|
*/
|
||||||
|
struct survey_results {
|
||||||
|
unsigned int freq_filter;
|
||||||
|
struct dl_list survey_list; /* struct freq_survey */
|
||||||
|
} survey_results;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,6 +84,7 @@ const char * event_to_string(enum wpa_event_type event)
|
|||||||
E2S(DFS_CAC_FINISHED);
|
E2S(DFS_CAC_FINISHED);
|
||||||
E2S(DFS_CAC_ABORTED);
|
E2S(DFS_CAC_ABORTED);
|
||||||
E2S(DFS_NOP_FINISHED);
|
E2S(DFS_NOP_FINISHED);
|
||||||
|
E2S(SURVEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
|
@ -9971,6 +9971,185 @@ static int nl80211_flush_pmkid(void *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void clean_survey_results(struct survey_results *survey_results)
|
||||||
|
{
|
||||||
|
struct freq_survey *survey, *tmp;
|
||||||
|
|
||||||
|
if (dl_list_empty(&survey_results->survey_list))
|
||||||
|
return;
|
||||||
|
|
||||||
|
dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
|
||||||
|
struct freq_survey, list) {
|
||||||
|
dl_list_del(&survey->list);
|
||||||
|
os_free(survey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void add_survey(struct nlattr **sinfo, u32 ifidx,
|
||||||
|
struct dl_list *survey_list)
|
||||||
|
{
|
||||||
|
struct freq_survey *survey;
|
||||||
|
|
||||||
|
survey = os_zalloc(sizeof(struct freq_survey));
|
||||||
|
if (!survey)
|
||||||
|
return;
|
||||||
|
|
||||||
|
survey->ifidx = ifidx;
|
||||||
|
survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
|
||||||
|
survey->filled = 0;
|
||||||
|
|
||||||
|
if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
|
||||||
|
survey->nf = (int8_t)
|
||||||
|
nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
|
||||||
|
survey->filled |= SURVEY_HAS_NF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
|
||||||
|
survey->channel_time =
|
||||||
|
nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
|
||||||
|
survey->filled |= SURVEY_HAS_CHAN_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
|
||||||
|
survey->channel_time_busy =
|
||||||
|
nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
|
||||||
|
survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
|
||||||
|
survey->channel_time_rx =
|
||||||
|
nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
|
||||||
|
survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
|
||||||
|
survey->channel_time_tx =
|
||||||
|
nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
|
||||||
|
survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Freq survey dump event (freq=%d MHz noise=%d channel_time=%ld busy_time=%ld tx_time=%ld rx_time=%ld filled=%04x)",
|
||||||
|
survey->freq,
|
||||||
|
survey->nf,
|
||||||
|
(unsigned long int) survey->channel_time,
|
||||||
|
(unsigned long int) survey->channel_time_busy,
|
||||||
|
(unsigned long int) survey->channel_time_tx,
|
||||||
|
(unsigned long int) survey->channel_time_rx,
|
||||||
|
survey->filled);
|
||||||
|
|
||||||
|
dl_list_add_tail(survey_list, &survey->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
|
||||||
|
unsigned int freq_filter)
|
||||||
|
{
|
||||||
|
if (!freq_filter)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return freq_filter == surveyed_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int survey_handler(struct nl_msg *msg, void *arg)
|
||||||
|
{
|
||||||
|
struct nlattr *tb[NL80211_ATTR_MAX + 1];
|
||||||
|
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
||||||
|
struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
|
||||||
|
struct survey_results *survey_results;
|
||||||
|
u32 surveyed_freq = 0;
|
||||||
|
u32 ifidx;
|
||||||
|
|
||||||
|
static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
|
||||||
|
[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
|
||||||
|
[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
|
||||||
|
};
|
||||||
|
|
||||||
|
survey_results = (struct survey_results *) arg;
|
||||||
|
|
||||||
|
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
||||||
|
genlmsg_attrlen(gnlh, 0), NULL);
|
||||||
|
|
||||||
|
ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
|
||||||
|
|
||||||
|
if (!tb[NL80211_ATTR_SURVEY_INFO])
|
||||||
|
return NL_SKIP;
|
||||||
|
|
||||||
|
if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
|
||||||
|
tb[NL80211_ATTR_SURVEY_INFO],
|
||||||
|
survey_policy))
|
||||||
|
return NL_SKIP;
|
||||||
|
|
||||||
|
if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
|
||||||
|
wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
|
||||||
|
return NL_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
|
||||||
|
|
||||||
|
if (!check_survey_ok(sinfo, surveyed_freq,
|
||||||
|
survey_results->freq_filter))
|
||||||
|
return NL_SKIP;
|
||||||
|
|
||||||
|
if (survey_results->freq_filter &&
|
||||||
|
survey_results->freq_filter != surveyed_freq) {
|
||||||
|
wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
|
||||||
|
surveyed_freq);
|
||||||
|
return NL_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_survey(sinfo, ifidx, &survey_results->survey_list);
|
||||||
|
|
||||||
|
return NL_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
|
||||||
|
{
|
||||||
|
struct i802_bss *bss = priv;
|
||||||
|
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||||
|
struct nl_msg *msg;
|
||||||
|
int err = -ENOBUFS;
|
||||||
|
union wpa_event_data data;
|
||||||
|
struct survey_results *survey_results;
|
||||||
|
|
||||||
|
os_memset(&data, 0, sizeof(data));
|
||||||
|
survey_results = &data.survey_results;
|
||||||
|
|
||||||
|
dl_list_init(&survey_results->survey_list);
|
||||||
|
|
||||||
|
msg = nlmsg_alloc();
|
||||||
|
if (!msg)
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
|
||||||
|
|
||||||
|
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
|
||||||
|
|
||||||
|
if (freq)
|
||||||
|
data.survey_results.freq_filter = freq;
|
||||||
|
|
||||||
|
do {
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
|
||||||
|
err = send_and_recv_msgs(drv, msg, survey_handler,
|
||||||
|
survey_results);
|
||||||
|
} while (err > 0);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
|
||||||
|
goto out_clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
|
||||||
|
|
||||||
|
out_clean:
|
||||||
|
clean_survey_results(survey_results);
|
||||||
|
nla_put_failure:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
|
static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
|
||||||
const u8 *replay_ctr)
|
const u8 *replay_ctr)
|
||||||
{
|
{
|
||||||
@ -10597,4 +10776,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
|||||||
#endif /* CONFIG_TDLS */
|
#endif /* CONFIG_TDLS */
|
||||||
.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
|
.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
|
||||||
.get_mac_addr = wpa_driver_nl80211_get_macaddr,
|
.get_mac_addr = wpa_driver_nl80211_get_macaddr,
|
||||||
|
.get_survey = wpa_driver_nl80211_get_survey,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user