hostapd: Add AP DFS support
Add DFS structures/events handlers, CAC handling, and radar detection. By default, after radar is detected or the channel became unavailable, a random channel will be chosen. This patches are based on the original work by Boris Presman and Victor Goldenshtein. Most of the DFS code is moved to a new dfs.c/dfs.h files. Cc: Boris Presman <boris.presman@ti.com> Cc: Victor Goldenshtein <victorg@ti.com> Signed-hostap: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-hostap: Janusz Dziedzic <janusz.dziedzic@tieto.com>
This commit is contained in:
parent
dfe6ce4eeb
commit
e76da50529
10 changed files with 423 additions and 10 deletions
|
@ -782,6 +782,7 @@ OBJS += ../src/ap/wmm.o
|
||||||
OBJS += ../src/ap/ap_list.o
|
OBJS += ../src/ap/ap_list.o
|
||||||
OBJS += ../src/ap/ieee802_11.o
|
OBJS += ../src/ap/ieee802_11.o
|
||||||
OBJS += ../src/ap/hw_features.o
|
OBJS += ../src/ap/hw_features.o
|
||||||
|
OBJS += ../src/ap/dfs.o
|
||||||
CFLAGS += -DNEED_AP_MLME
|
CFLAGS += -DNEED_AP_MLME
|
||||||
endif
|
endif
|
||||||
ifdef CONFIG_IEEE80211N
|
ifdef CONFIG_IEEE80211N
|
||||||
|
|
|
@ -699,3 +699,30 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
|
||||||
hapd->own_addr, hapd->own_addr, data,
|
hapd->own_addr, hapd->own_addr, data,
|
||||||
len, 0);
|
len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_start_dfs_cac(struct hostapd_data *hapd, int freq, int flags)
|
||||||
|
{
|
||||||
|
if (!hapd->driver || !hapd->driver->start_dfs_cac)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(flags & HOSTAPD_CHAN_RADAR)) {
|
||||||
|
wpa_printf(MSG_ERROR, "Can't start DFS_CAC, the channel %u is "
|
||||||
|
"not DFS channel", hapd->iconf->channel);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hapd->iface->conf->ieee80211h) {
|
||||||
|
wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality "
|
||||||
|
"is not enabled");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hapd->iface->conf->secondary_channel) {
|
||||||
|
wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality "
|
||||||
|
"on HT40 is not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hapd->driver->start_dfs_cac(hapd->drv_priv, freq);
|
||||||
|
}
|
||||||
|
|
|
@ -101,6 +101,7 @@ int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||||
int reassoc, u16 status, const u8 *ie, size_t len);
|
int reassoc, u16 status, const u8 *ie, size_t len);
|
||||||
int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
|
int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
|
||||||
u8 *tspec_ie, size_t tspec_ielen);
|
u8 *tspec_ie, size_t tspec_ielen);
|
||||||
|
int hostapd_start_dfs_cac(struct hostapd_data *hapd, int freq, int flags);
|
||||||
|
|
||||||
|
|
||||||
#include "drivers/driver.h"
|
#include "drivers/driver.h"
|
||||||
|
|
207
src/ap/dfs.c
Normal file
207
src/ap/dfs.c
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
/*
|
||||||
|
* DFS - Dynamic Frequency Selection
|
||||||
|
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "utils/includes.h"
|
||||||
|
|
||||||
|
#include "utils/common.h"
|
||||||
|
#include "common/ieee802_11_defs.h"
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "hw_features.h"
|
||||||
|
#include "ap_drv_ops.h"
|
||||||
|
#include "drivers/driver.h"
|
||||||
|
#include "dfs.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_dfs_find_channel(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_channel_data **ret_chan,
|
||||||
|
int idx)
|
||||||
|
{
|
||||||
|
struct hostapd_hw_modes *mode;
|
||||||
|
struct hostapd_channel_data *chan;
|
||||||
|
int i, channel_idx = 0;
|
||||||
|
|
||||||
|
mode = hapd->iface->current_mode;
|
||||||
|
|
||||||
|
for (i = 0; i < mode->num_channels; i++) {
|
||||||
|
chan = &mode->channels[i];
|
||||||
|
|
||||||
|
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (chan->flag & HOSTAPD_CHAN_RADAR &&
|
||||||
|
chan->flag & HOSTAPD_CHAN_DFS_UNAVAILABLE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ret_chan && idx == channel_idx) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
|
||||||
|
*ret_chan = chan;
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
channel_idx++;
|
||||||
|
}
|
||||||
|
return channel_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct hostapd_channel_data * hostapd_dfs_get_valid_channel(
|
||||||
|
struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct hostapd_hw_modes *mode;
|
||||||
|
struct hostapd_channel_data *chan = NULL;
|
||||||
|
int channel_idx, new_channel_idx;
|
||||||
|
u32 _rand;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
|
||||||
|
|
||||||
|
if (hapd->iface->current_mode == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mode = hapd->iface->current_mode;
|
||||||
|
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* get random available channel */
|
||||||
|
channel_idx = hostapd_dfs_find_channel(hapd, NULL, 0);
|
||||||
|
if (channel_idx > 0) {
|
||||||
|
os_get_random((u8 *) &_rand, sizeof(_rand));
|
||||||
|
new_channel_idx = _rand % channel_idx;
|
||||||
|
hostapd_dfs_find_channel(hapd, &chan, new_channel_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ieee802_11_set_dfs_state(struct hostapd_data *hapd, int freq, u32 state)
|
||||||
|
{
|
||||||
|
struct hostapd_hw_modes *mode;
|
||||||
|
struct hostapd_channel_data *chan = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mode = hapd->iface->current_mode;
|
||||||
|
if (mode == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
|
||||||
|
wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
|
||||||
|
chan = &hapd->iface->current_mode->channels[i];
|
||||||
|
if (chan->freq == freq) {
|
||||||
|
if (chan->flag & HOSTAPD_CHAN_RADAR) {
|
||||||
|
chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
|
||||||
|
chan->flag |= state;
|
||||||
|
return 1; /* Channel found */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main DFS handler
|
||||||
|
* 1 - continue channel/ap setup
|
||||||
|
* 0 - channel/ap setup will be continued after CAC
|
||||||
|
* -1 - hit critical error
|
||||||
|
*/
|
||||||
|
int hostapd_handle_dfs(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
struct hostapd_channel_data *channel;
|
||||||
|
|
||||||
|
/* Handle DFS channel */
|
||||||
|
check_dfs_chan_again:
|
||||||
|
flags = hostapd_hw_get_channel_flag(hapd, hapd->iconf->channel);
|
||||||
|
if (flags & HOSTAPD_CHAN_RADAR) {
|
||||||
|
switch (flags & HOSTAPD_CHAN_DFS_MASK) {
|
||||||
|
case HOSTAPD_CHAN_DFS_USABLE:
|
||||||
|
wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz",
|
||||||
|
hapd->iface->freq);
|
||||||
|
if (hostapd_start_dfs_cac(hapd,
|
||||||
|
hapd->iface->freq,
|
||||||
|
flags)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Continue initialisation after CAC */
|
||||||
|
return 0;
|
||||||
|
case HOSTAPD_CHAN_DFS_UNAVAILABLE:
|
||||||
|
wpa_printf(MSG_DEBUG, "HOSTAPD_CHAN_DFS_UNAVAILABLE, get new chan");
|
||||||
|
/* find other channel here */
|
||||||
|
channel = hostapd_dfs_get_valid_channel(hapd);
|
||||||
|
if (!channel) {
|
||||||
|
wpa_printf(MSG_ERROR, "could not get valid channel");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
hapd->iconf->channel = channel->chan;
|
||||||
|
hapd->iface->freq = channel->freq;
|
||||||
|
goto check_dfs_chan_again;
|
||||||
|
case HOSTAPD_CHAN_DFS_AVAILABLE:
|
||||||
|
/* We don't need CAC here */
|
||||||
|
wpa_printf(MSG_DEBUG, "HOSTAPD_CHAN_DFS_AVAILABLE, skip CAC");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ieee802_11_complete_cac(struct hostapd_data *hapd, int success, int freq)
|
||||||
|
{
|
||||||
|
struct hostapd_channel_data *channel;
|
||||||
|
int err = 1;
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
/* Complete iface/ap configuration */
|
||||||
|
ieee802_11_set_dfs_state(hapd, freq,
|
||||||
|
HOSTAPD_CHAN_DFS_AVAILABLE);
|
||||||
|
hostapd_setup_interface_complete(hapd->iface, 0);
|
||||||
|
} else {
|
||||||
|
/* Switch to new channel */
|
||||||
|
ieee802_11_set_dfs_state(hapd, freq,
|
||||||
|
HOSTAPD_CHAN_DFS_UNAVAILABLE);
|
||||||
|
channel = hostapd_dfs_get_valid_channel(hapd);
|
||||||
|
if (channel) {
|
||||||
|
hapd->iconf->channel = channel->chan;
|
||||||
|
hapd->iface->freq = channel->freq;
|
||||||
|
err = 0;
|
||||||
|
} else
|
||||||
|
wpa_printf(MSG_ERROR, "No valid channel available");
|
||||||
|
|
||||||
|
hostapd_setup_interface_complete(hapd->iface, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ieee802_11_start_channel_switch(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct hostapd_channel_data *channel;
|
||||||
|
int err = 1;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s called", __func__);
|
||||||
|
channel = hostapd_dfs_get_valid_channel(hapd);
|
||||||
|
if (channel) {
|
||||||
|
hapd->iconf->channel = channel->chan;
|
||||||
|
hapd->iface->freq = channel->freq;
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hapd->driver->stop_ap(hapd->drv_priv);
|
||||||
|
|
||||||
|
hostapd_setup_interface_complete(hapd->iface, err);
|
||||||
|
return 0;
|
||||||
|
}
|
18
src/ap/dfs.h
Normal file
18
src/ap/dfs.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* DFS - Dynamic Frequency Selection
|
||||||
|
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
#ifndef DFS_H
|
||||||
|
#define DFS_H
|
||||||
|
|
||||||
|
struct hostapd_channel_data * hostapd_dfs_get_valid_channel(
|
||||||
|
struct hostapd_data *hapd);
|
||||||
|
int ieee802_11_complete_cac(struct hostapd_data *hapd, int success, int freq);
|
||||||
|
int ieee802_11_set_dfs_state(struct hostapd_data *hapd, int freq, u32 state);
|
||||||
|
int ieee802_11_start_channel_switch(struct hostapd_data *hapd);
|
||||||
|
int hostapd_handle_dfs(struct hostapd_data *hapd);
|
||||||
|
|
||||||
|
#endif /* DFS_H */
|
|
@ -29,6 +29,7 @@
|
||||||
#include "ap_drv_ops.h"
|
#include "ap_drv_ops.h"
|
||||||
#include "ap_config.h"
|
#include "ap_config.h"
|
||||||
#include "hw_features.h"
|
#include "hw_features.h"
|
||||||
|
#include "dfs.h"
|
||||||
|
|
||||||
|
|
||||||
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||||
|
@ -785,6 +786,61 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef NEED_AP_MLME
|
||||||
|
|
||||||
|
static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
|
||||||
|
struct dfs_event *radar)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
|
||||||
|
|
||||||
|
if (!hapd->iconf->ieee80211h)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* mark radar frequency as invalid */
|
||||||
|
res = ieee802_11_set_dfs_state(hapd, radar->freq,
|
||||||
|
HOSTAPD_CHAN_DFS_UNAVAILABLE);
|
||||||
|
|
||||||
|
/* other frequency, just mark it and return. */
|
||||||
|
if (hapd->iface->freq != radar->freq)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* we are working on non-DFS channel - skip event */
|
||||||
|
if (res == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* radar detected while operating, switch the channel. */
|
||||||
|
ieee802_11_start_channel_switch(hapd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
|
||||||
|
struct dfs_event *radar)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
|
||||||
|
ieee802_11_complete_cac(hapd, 1, radar->freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd,
|
||||||
|
struct dfs_event *radar)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
|
||||||
|
ieee802_11_complete_cac(hapd, 0, radar->freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
|
||||||
|
struct dfs_event *radar)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
|
||||||
|
ieee802_11_set_dfs_state(hapd, radar->freq, HOSTAPD_CHAN_DFS_USABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* NEED_AP_MLME */
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -929,6 +985,34 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
case EVENT_SURVEY:
|
case EVENT_SURVEY:
|
||||||
hostapd_event_get_survey(hapd, &data->survey_results);
|
hostapd_event_get_survey(hapd, &data->survey_results);
|
||||||
break;
|
break;
|
||||||
|
#ifdef NEED_AP_MLME
|
||||||
|
case EVENT_DFS_RADAR_DETECTED:
|
||||||
|
if (!data)
|
||||||
|
break;
|
||||||
|
hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
|
||||||
|
break;
|
||||||
|
case EVENT_DFS_CAC_FINISHED:
|
||||||
|
if (!data)
|
||||||
|
break;
|
||||||
|
hostapd_event_dfs_cac_finished(hapd, &data->dfs_event);
|
||||||
|
break;
|
||||||
|
case EVENT_DFS_CAC_ABORTED:
|
||||||
|
if (!data)
|
||||||
|
break;
|
||||||
|
hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event);
|
||||||
|
break;
|
||||||
|
case EVENT_DFS_NOP_FINISHED:
|
||||||
|
if (!data)
|
||||||
|
break;
|
||||||
|
hostapd_event_dfs_nop_finished(hapd, &data->dfs_event);
|
||||||
|
break;
|
||||||
|
case EVENT_CHANNEL_LIST_CHANGED:
|
||||||
|
/* channel list changed (regulatory?), update channel list */
|
||||||
|
/* TODO: check this. hostapd_get_hw_features() initializes
|
||||||
|
* too much stuff. */
|
||||||
|
/* hostapd_get_hw_features(hapd->iface); */
|
||||||
|
break;
|
||||||
|
#endif /* NEED_AP_MLME */
|
||||||
default:
|
default:
|
||||||
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
|
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "ap_config.h"
|
#include "ap_config.h"
|
||||||
#include "p2p_hostapd.h"
|
#include "p2p_hostapd.h"
|
||||||
#include "gas_serv.h"
|
#include "gas_serv.h"
|
||||||
|
#include "dfs.h"
|
||||||
|
|
||||||
|
|
||||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
|
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
|
||||||
|
@ -931,6 +932,9 @@ static int setup_interface(struct hostapd_iface *iface)
|
||||||
"be completed in a callback");
|
"be completed in a callback");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iface->conf->ieee80211h)
|
||||||
|
wpa_printf(MSG_DEBUG, "DFS support is enabled");
|
||||||
}
|
}
|
||||||
return hostapd_setup_interface_complete(iface, 0);
|
return hostapd_setup_interface_complete(iface, 0);
|
||||||
}
|
}
|
||||||
|
@ -950,12 +954,23 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "Completing interface initialization");
|
wpa_printf(MSG_DEBUG, "Completing interface initialization");
|
||||||
if (hapd->iconf->channel) {
|
if (hapd->iconf->channel) {
|
||||||
|
#ifdef NEED_AP_MLME
|
||||||
|
int res;
|
||||||
|
#endif /* NEED_AP_MLME */
|
||||||
|
|
||||||
iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
|
iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
|
||||||
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
|
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
|
||||||
"Frequency: %d MHz",
|
"Frequency: %d MHz",
|
||||||
hostapd_hw_mode_txt(hapd->iconf->hw_mode),
|
hostapd_hw_mode_txt(hapd->iconf->hw_mode),
|
||||||
hapd->iconf->channel, iface->freq);
|
hapd->iconf->channel, iface->freq);
|
||||||
|
|
||||||
|
#ifdef NEED_AP_MLME
|
||||||
|
/* Check DFS */
|
||||||
|
res = hostapd_handle_dfs(hapd);
|
||||||
|
if (res <= 0)
|
||||||
|
return res;
|
||||||
|
#endif /* NEED_AP_MLME */
|
||||||
|
|
||||||
if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
|
if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
|
||||||
hapd->iconf->channel,
|
hapd->iconf->channel,
|
||||||
hapd->iconf->ieee80211n,
|
hapd->iconf->ieee80211n,
|
||||||
|
|
|
@ -45,6 +45,36 @@ void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef CONFIG_NO_STDOUT_DEBUG
|
||||||
|
static char * dfs_info(struct hostapd_channel_data *chan)
|
||||||
|
{
|
||||||
|
static char info[256];
|
||||||
|
char *state;
|
||||||
|
|
||||||
|
switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) {
|
||||||
|
case HOSTAPD_CHAN_DFS_UNKNOWN:
|
||||||
|
state = "unknown";
|
||||||
|
break;
|
||||||
|
case HOSTAPD_CHAN_DFS_USABLE:
|
||||||
|
state = "usable";
|
||||||
|
break;
|
||||||
|
case HOSTAPD_CHAN_DFS_UNAVAILABLE:
|
||||||
|
state = "unavailable";
|
||||||
|
break;
|
||||||
|
case HOSTAPD_CHAN_DFS_AVAILABLE:
|
||||||
|
state = "available";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
os_snprintf(info, sizeof(info), " (DFS state = %s)", state);
|
||||||
|
info[sizeof(info) - 1] = '\0';
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||||
|
|
||||||
|
|
||||||
int hostapd_get_hw_features(struct hostapd_iface *iface)
|
int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||||
{
|
{
|
||||||
struct hostapd_data *hapd = iface->bss[0];
|
struct hostapd_data *hapd = iface->bss[0];
|
||||||
|
@ -71,30 +101,40 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||||
|
|
||||||
for (i = 0; i < num_modes; i++) {
|
for (i = 0; i < num_modes; i++) {
|
||||||
struct hostapd_hw_modes *feature = &modes[i];
|
struct hostapd_hw_modes *feature = &modes[i];
|
||||||
|
int dfs_enabled = hapd->iconf->ieee80211h &&
|
||||||
|
(iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
|
||||||
|
|
||||||
/* set flag for channels we can use in current regulatory
|
/* set flag for channels we can use in current regulatory
|
||||||
* domain */
|
* domain */
|
||||||
for (j = 0; j < feature->num_channels; j++) {
|
for (j = 0; j < feature->num_channels; j++) {
|
||||||
|
int dfs = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable all channels that are marked not to allow
|
* Disable all channels that are marked not to allow
|
||||||
* IBSS operation or active scanning. In addition,
|
* IBSS operation or active scanning.
|
||||||
* disable all channels that require radar detection,
|
* Use radar channels only if the driver supports DFS.
|
||||||
* since that (in addition to full DFS) is not yet
|
|
||||||
* supported.
|
|
||||||
*/
|
*/
|
||||||
if (feature->channels[j].flag &
|
if ((feature->channels[j].flag &
|
||||||
(HOSTAPD_CHAN_NO_IBSS |
|
HOSTAPD_CHAN_RADAR) && dfs_enabled) {
|
||||||
HOSTAPD_CHAN_PASSIVE_SCAN |
|
dfs = 1;
|
||||||
HOSTAPD_CHAN_RADAR))
|
} else if (feature->channels[j].flag &
|
||||||
|
(HOSTAPD_CHAN_NO_IBSS |
|
||||||
|
HOSTAPD_CHAN_PASSIVE_SCAN |
|
||||||
|
HOSTAPD_CHAN_RADAR)) {
|
||||||
feature->channels[j].flag |=
|
feature->channels[j].flag |=
|
||||||
HOSTAPD_CHAN_DISABLED;
|
HOSTAPD_CHAN_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
|
if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
|
wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
|
||||||
"chan=%d freq=%d MHz max_tx_power=%d dBm",
|
"chan=%d freq=%d MHz max_tx_power=%d dBm%s",
|
||||||
feature->mode,
|
feature->mode,
|
||||||
feature->channels[j].chan,
|
feature->channels[j].chan,
|
||||||
feature->channels[j].freq,
|
feature->channels[j].freq,
|
||||||
feature->channels[j].max_tx_power);
|
feature->channels[j].max_tx_power,
|
||||||
|
dfs ? dfs_info(&feature->channels[j]) : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,3 +889,21 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_hw_get_channel_flag(struct hostapd_data *hapd, int chan)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!hapd->iface->current_mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
|
||||||
|
struct hostapd_channel_data *ch =
|
||||||
|
&hapd->iface->current_mode->channels[i];
|
||||||
|
if (ch->chan == chan)
|
||||||
|
return ch->flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
|
||||||
int hostapd_check_ht_capab(struct hostapd_iface *iface);
|
int hostapd_check_ht_capab(struct hostapd_iface *iface);
|
||||||
int hostapd_prepare_rates(struct hostapd_iface *iface,
|
int hostapd_prepare_rates(struct hostapd_iface *iface,
|
||||||
struct hostapd_hw_modes *mode);
|
struct hostapd_hw_modes *mode);
|
||||||
|
int hostapd_hw_get_channel_flag(struct hostapd_data *hapd, int chan);
|
||||||
#else /* NEED_AP_MLME */
|
#else /* NEED_AP_MLME */
|
||||||
static inline void
|
static inline void
|
||||||
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||||
|
|
|
@ -772,6 +772,7 @@ OBJS += ../src/ap/wmm.o
|
||||||
OBJS += ../src/ap/ap_list.o
|
OBJS += ../src/ap/ap_list.o
|
||||||
OBJS += ../src/ap/ieee802_11.o
|
OBJS += ../src/ap/ieee802_11.o
|
||||||
OBJS += ../src/ap/hw_features.o
|
OBJS += ../src/ap/hw_features.o
|
||||||
|
OBJS += ../src/ap/dfs.o
|
||||||
CFLAGS += -DNEED_AP_MLME
|
CFLAGS += -DNEED_AP_MLME
|
||||||
endif
|
endif
|
||||||
ifdef CONFIG_WPS
|
ifdef CONFIG_WPS
|
||||||
|
|
Loading…
Reference in a new issue