2009-08-07 19:22:35 +04:00
/*
* This file contains helper code to handle channel
* settings and keeping track of what is possible at
* any point in time .
*
* Copyright 2009 Johannes Berg < johannes @ sipsolutions . net >
*/
2011-11-30 19:56:32 +04:00
# include <linux/export.h>
2009-08-07 19:22:35 +04:00
# include <net/cfg80211.h>
# include "core.h"
2012-06-27 18:19:42 +04:00
# include "rdev-ops.h"
2009-08-07 19:22:35 +04:00
2012-11-09 02:14:50 +04:00
void cfg80211_chandef_create ( struct cfg80211_chan_def * chandef ,
struct ieee80211_channel * chan ,
enum nl80211_channel_type chan_type )
2010-11-13 03:31:23 +03:00
{
2012-11-09 02:14:50 +04:00
if ( WARN_ON ( ! chan ) )
return ;
2010-11-13 03:31:23 +03:00
2012-11-09 02:14:50 +04:00
chandef - > chan = chan ;
chandef - > center_freq2 = 0 ;
2012-08-27 13:49:39 +04:00
2012-11-09 02:14:50 +04:00
switch ( chan_type ) {
case NL80211_CHAN_NO_HT :
chandef - > width = NL80211_CHAN_WIDTH_20_NOHT ;
chandef - > center_freq1 = chan - > center_freq ;
break ;
case NL80211_CHAN_HT20 :
chandef - > width = NL80211_CHAN_WIDTH_20 ;
chandef - > center_freq1 = chan - > center_freq ;
break ;
2010-11-13 03:31:23 +03:00
case NL80211_CHAN_HT40PLUS :
2012-11-09 02:14:50 +04:00
chandef - > width = NL80211_CHAN_WIDTH_40 ;
chandef - > center_freq1 = chan - > center_freq + 10 ;
2010-11-18 00:34:37 +03:00
break ;
2010-11-13 03:31:23 +03:00
case NL80211_CHAN_HT40MINUS :
2012-11-09 02:14:50 +04:00
chandef - > width = NL80211_CHAN_WIDTH_40 ;
chandef - > center_freq1 = chan - > center_freq - 10 ;
2010-11-18 00:34:37 +03:00
break ;
2010-11-13 03:31:23 +03:00
default :
2012-11-09 02:14:50 +04:00
WARN_ON ( 1 ) ;
}
}
EXPORT_SYMBOL ( cfg80211_chandef_create ) ;
2012-11-22 19:59:45 +04:00
bool cfg80211_chandef_valid ( const struct cfg80211_chan_def * chandef )
2012-11-09 02:14:50 +04:00
{
u32 control_freq ;
if ( ! chandef - > chan )
return false ;
control_freq = chandef - > chan - > center_freq ;
switch ( chandef - > width ) {
2013-05-16 15:00:28 +04:00
case NL80211_CHAN_WIDTH_5 :
case NL80211_CHAN_WIDTH_10 :
2012-11-09 02:14:50 +04:00
case NL80211_CHAN_WIDTH_20 :
case NL80211_CHAN_WIDTH_20_NOHT :
if ( chandef - > center_freq1 ! = control_freq )
return false ;
if ( chandef - > center_freq2 )
return false ;
break ;
case NL80211_CHAN_WIDTH_40 :
if ( chandef - > center_freq1 ! = control_freq + 10 & &
chandef - > center_freq1 ! = control_freq - 10 )
return false ;
if ( chandef - > center_freq2 )
return false ;
break ;
case NL80211_CHAN_WIDTH_80P80 :
if ( chandef - > center_freq1 ! = control_freq + 30 & &
chandef - > center_freq1 ! = control_freq + 10 & &
chandef - > center_freq1 ! = control_freq - 10 & &
chandef - > center_freq1 ! = control_freq - 30 )
return false ;
if ( ! chandef - > center_freq2 )
return false ;
2012-12-14 03:19:08 +04:00
/* adjacent is not allowed -- that's a 160 MHz channel */
if ( chandef - > center_freq1 - chandef - > center_freq2 = = 80 | |
chandef - > center_freq2 - chandef - > center_freq1 = = 80 )
return false ;
2012-11-09 02:14:50 +04:00
break ;
case NL80211_CHAN_WIDTH_80 :
if ( chandef - > center_freq1 ! = control_freq + 30 & &
chandef - > center_freq1 ! = control_freq + 10 & &
chandef - > center_freq1 ! = control_freq - 10 & &
chandef - > center_freq1 ! = control_freq - 30 )
return false ;
if ( chandef - > center_freq2 )
return false ;
break ;
case NL80211_CHAN_WIDTH_160 :
if ( chandef - > center_freq1 ! = control_freq + 70 & &
chandef - > center_freq1 ! = control_freq + 50 & &
chandef - > center_freq1 ! = control_freq + 30 & &
chandef - > center_freq1 ! = control_freq + 10 & &
chandef - > center_freq1 ! = control_freq - 10 & &
chandef - > center_freq1 ! = control_freq - 30 & &
chandef - > center_freq1 ! = control_freq - 50 & &
chandef - > center_freq1 ! = control_freq - 70 )
return false ;
if ( chandef - > center_freq2 )
return false ;
break ;
default :
return false ;
}
return true ;
}
2012-11-22 19:59:45 +04:00
EXPORT_SYMBOL ( cfg80211_chandef_valid ) ;
2012-11-09 02:14:50 +04:00
static void chandef_primary_freqs ( const struct cfg80211_chan_def * c ,
int * pri40 , int * pri80 )
{
int tmp ;
switch ( c - > width ) {
case NL80211_CHAN_WIDTH_40 :
* pri40 = c - > center_freq1 ;
* pri80 = 0 ;
break ;
case NL80211_CHAN_WIDTH_80 :
case NL80211_CHAN_WIDTH_80P80 :
* pri80 = c - > center_freq1 ;
/* n_P20 */
tmp = ( 30 + c - > chan - > center_freq - c - > center_freq1 ) / 20 ;
/* n_P40 */
tmp / = 2 ;
/* freq_P40 */
* pri40 = c - > center_freq1 - 20 + 40 * tmp ;
break ;
case NL80211_CHAN_WIDTH_160 :
/* n_P20 */
tmp = ( 70 + c - > chan - > center_freq - c - > center_freq1 ) / 20 ;
/* n_P40 */
tmp / = 2 ;
/* freq_P40 */
* pri40 = c - > center_freq1 - 60 + 40 * tmp ;
/* n_P80 */
tmp / = 2 ;
* pri80 = c - > center_freq1 - 40 + 80 * tmp ;
break ;
default :
WARN_ON_ONCE ( 1 ) ;
}
}
2013-02-08 21:16:19 +04:00
static int cfg80211_chandef_get_width ( const struct cfg80211_chan_def * c )
{
int width ;
switch ( c - > width ) {
2013-05-16 15:00:28 +04:00
case NL80211_CHAN_WIDTH_5 :
width = 5 ;
break ;
case NL80211_CHAN_WIDTH_10 :
width = 10 ;
break ;
2013-02-08 21:16:19 +04:00
case NL80211_CHAN_WIDTH_20 :
case NL80211_CHAN_WIDTH_20_NOHT :
width = 20 ;
break ;
case NL80211_CHAN_WIDTH_40 :
width = 40 ;
break ;
case NL80211_CHAN_WIDTH_80P80 :
case NL80211_CHAN_WIDTH_80 :
width = 80 ;
break ;
case NL80211_CHAN_WIDTH_160 :
width = 160 ;
break ;
default :
WARN_ON_ONCE ( 1 ) ;
return - 1 ;
}
return width ;
}
2012-11-09 02:14:50 +04:00
const struct cfg80211_chan_def *
cfg80211_chandef_compatible ( const struct cfg80211_chan_def * c1 ,
const struct cfg80211_chan_def * c2 )
{
u32 c1_pri40 , c1_pri80 , c2_pri40 , c2_pri80 ;
/* If they are identical, return */
if ( cfg80211_chandef_identical ( c1 , c2 ) )
return c1 ;
/* otherwise, must have same control channel */
if ( c1 - > chan ! = c2 - > chan )
return NULL ;
/*
* If they have the same width , but aren ' t identical ,
* then they can ' t be compatible .
*/
if ( c1 - > width = = c2 - > width )
return NULL ;
2013-05-16 15:00:28 +04:00
/*
* can ' t be compatible if one of them is 5 or 10 MHz ,
* but they don ' t have the same width .
*/
if ( c1 - > width = = NL80211_CHAN_WIDTH_5 | |
c1 - > width = = NL80211_CHAN_WIDTH_10 | |
c2 - > width = = NL80211_CHAN_WIDTH_5 | |
c2 - > width = = NL80211_CHAN_WIDTH_10 )
return NULL ;
2012-11-09 02:14:50 +04:00
if ( c1 - > width = = NL80211_CHAN_WIDTH_20_NOHT | |
c1 - > width = = NL80211_CHAN_WIDTH_20 )
return c2 ;
if ( c2 - > width = = NL80211_CHAN_WIDTH_20_NOHT | |
c2 - > width = = NL80211_CHAN_WIDTH_20 )
return c1 ;
chandef_primary_freqs ( c1 , & c1_pri40 , & c1_pri80 ) ;
chandef_primary_freqs ( c2 , & c2_pri40 , & c2_pri80 ) ;
if ( c1_pri40 ! = c2_pri40 )
return NULL ;
WARN_ON ( ! c1_pri80 & & ! c2_pri80 ) ;
if ( c1_pri80 & & c2_pri80 & & c1_pri80 ! = c2_pri80 )
return NULL ;
if ( c1 - > width > c2 - > width )
return c1 ;
return c2 ;
}
EXPORT_SYMBOL ( cfg80211_chandef_compatible ) ;
2013-02-08 21:16:19 +04:00
static void cfg80211_set_chans_dfs_state ( struct wiphy * wiphy , u32 center_freq ,
u32 bandwidth ,
enum nl80211_dfs_state dfs_state )
{
struct ieee80211_channel * c ;
u32 freq ;
for ( freq = center_freq - bandwidth / 2 + 10 ;
freq < = center_freq + bandwidth / 2 - 10 ;
freq + = 20 ) {
c = ieee80211_get_channel ( wiphy , freq ) ;
if ( ! c | | ! ( c - > flags & IEEE80211_CHAN_RADAR ) )
continue ;
c - > dfs_state = dfs_state ;
c - > dfs_state_entered = jiffies ;
}
}
void cfg80211_set_dfs_state ( struct wiphy * wiphy ,
const struct cfg80211_chan_def * chandef ,
enum nl80211_dfs_state dfs_state )
{
int width ;
if ( WARN_ON ( ! cfg80211_chandef_valid ( chandef ) ) )
return ;
width = cfg80211_chandef_get_width ( chandef ) ;
if ( width < 0 )
return ;
cfg80211_set_chans_dfs_state ( wiphy , chandef - > center_freq1 ,
width , dfs_state ) ;
if ( ! chandef - > center_freq2 )
return ;
cfg80211_set_chans_dfs_state ( wiphy , chandef - > center_freq2 ,
width , dfs_state ) ;
}
2013-11-05 17:48:47 +04:00
static u32 cfg80211_get_start_freq ( u32 center_freq ,
u32 bandwidth )
{
u32 start_freq ;
if ( bandwidth < = 20 )
start_freq = center_freq ;
else
start_freq = center_freq - bandwidth / 2 + 10 ;
return start_freq ;
}
static u32 cfg80211_get_end_freq ( u32 center_freq ,
u32 bandwidth )
{
u32 end_freq ;
if ( bandwidth < = 20 )
end_freq = center_freq ;
else
end_freq = center_freq + bandwidth / 2 - 10 ;
return end_freq ;
}
2013-02-08 21:16:19 +04:00
static int cfg80211_get_chans_dfs_required ( struct wiphy * wiphy ,
u32 center_freq ,
u32 bandwidth )
{
struct ieee80211_channel * c ;
2013-05-16 15:00:28 +04:00
u32 freq , start_freq , end_freq ;
2013-11-05 17:48:47 +04:00
start_freq = cfg80211_get_start_freq ( center_freq , bandwidth ) ;
end_freq = cfg80211_get_end_freq ( center_freq , bandwidth ) ;
2013-02-08 21:16:19 +04:00
2013-05-16 15:00:28 +04:00
for ( freq = start_freq ; freq < = end_freq ; freq + = 20 ) {
2013-02-08 21:16:19 +04:00
c = ieee80211_get_channel ( wiphy , freq ) ;
if ( ! c )
return - EINVAL ;
if ( c - > flags & IEEE80211_CHAN_RADAR )
return 1 ;
}
return 0 ;
}
int cfg80211_chandef_dfs_required ( struct wiphy * wiphy ,
const struct cfg80211_chan_def * chandef )
{
int width ;
int r ;
if ( WARN_ON ( ! cfg80211_chandef_valid ( chandef ) ) )
return - EINVAL ;
width = cfg80211_chandef_get_width ( chandef ) ;
if ( width < 0 )
return - EINVAL ;
r = cfg80211_get_chans_dfs_required ( wiphy , chandef - > center_freq1 ,
width ) ;
if ( r )
return r ;
if ( ! chandef - > center_freq2 )
return 0 ;
return cfg80211_get_chans_dfs_required ( wiphy , chandef - > center_freq2 ,
width ) ;
}
2013-08-28 15:41:28 +04:00
EXPORT_SYMBOL ( cfg80211_chandef_dfs_required ) ;
2013-02-08 21:16:19 +04:00
2013-11-05 17:48:48 +04:00
static int cfg80211_get_chans_dfs_usable ( struct wiphy * wiphy ,
u32 center_freq ,
u32 bandwidth )
{
struct ieee80211_channel * c ;
u32 freq , start_freq , end_freq ;
int count = 0 ;
start_freq = cfg80211_get_start_freq ( center_freq , bandwidth ) ;
end_freq = cfg80211_get_end_freq ( center_freq , bandwidth ) ;
/*
* Check entire range of channels for the bandwidth .
* Check all channels are DFS channels ( DFS_USABLE or
* DFS_AVAILABLE ) . Return number of usable channels
* ( require CAC ) . Allow DFS and non - DFS channel mix .
*/
for ( freq = start_freq ; freq < = end_freq ; freq + = 20 ) {
c = ieee80211_get_channel ( wiphy , freq ) ;
if ( ! c )
return - EINVAL ;
if ( c - > flags & IEEE80211_CHAN_DISABLED )
return - EINVAL ;
if ( c - > flags & IEEE80211_CHAN_RADAR ) {
if ( c - > dfs_state = = NL80211_DFS_UNAVAILABLE )
return - EINVAL ;
if ( c - > dfs_state = = NL80211_DFS_USABLE )
count + + ;
}
}
return count ;
}
bool cfg80211_chandef_dfs_usable ( struct wiphy * wiphy ,
const struct cfg80211_chan_def * chandef )
{
int width ;
int r1 , r2 = 0 ;
if ( WARN_ON ( ! cfg80211_chandef_valid ( chandef ) ) )
return false ;
width = cfg80211_chandef_get_width ( chandef ) ;
if ( width < 0 )
return false ;
r1 = cfg80211_get_chans_dfs_usable ( wiphy , chandef - > center_freq1 ,
width ) ;
if ( r1 < 0 )
return false ;
switch ( chandef - > width ) {
case NL80211_CHAN_WIDTH_80P80 :
WARN_ON ( ! chandef - > center_freq2 ) ;
r2 = cfg80211_get_chans_dfs_usable ( wiphy ,
chandef - > center_freq2 ,
width ) ;
if ( r2 < 0 )
return false ;
break ;
default :
WARN_ON ( chandef - > center_freq2 ) ;
break ;
}
return ( r1 + r2 > 0 ) ;
}
2012-11-22 19:59:45 +04:00
static bool cfg80211_secondary_chans_ok ( struct wiphy * wiphy ,
u32 center_freq , u32 bandwidth ,
u32 prohibited_flags )
2012-11-09 02:14:50 +04:00
{
struct ieee80211_channel * c ;
2013-05-16 15:00:28 +04:00
u32 freq , start_freq , end_freq ;
2013-11-05 17:48:47 +04:00
start_freq = cfg80211_get_start_freq ( center_freq , bandwidth ) ;
end_freq = cfg80211_get_end_freq ( center_freq , bandwidth ) ;
2012-11-09 02:14:50 +04:00
2013-05-16 15:00:28 +04:00
for ( freq = start_freq ; freq < = end_freq ; freq + = 20 ) {
2012-11-09 02:14:50 +04:00
c = ieee80211_get_channel ( wiphy , freq ) ;
2013-02-08 21:16:19 +04:00
if ( ! c )
return false ;
/* check for radar flags */
if ( ( prohibited_flags & c - > flags & IEEE80211_CHAN_RADAR ) & &
( c - > dfs_state ! = NL80211_DFS_AVAILABLE ) )
return false ;
/* check for the other flags */
if ( c - > flags & prohibited_flags & ~ IEEE80211_CHAN_RADAR )
2012-11-09 02:14:50 +04:00
return false ;
2010-11-13 03:31:23 +03:00
}
2012-11-09 02:14:50 +04:00
return true ;
}
2012-11-22 19:59:45 +04:00
bool cfg80211_chandef_usable ( struct wiphy * wiphy ,
const struct cfg80211_chan_def * chandef ,
u32 prohibited_flags )
2012-11-09 02:14:50 +04:00
{
2012-11-22 19:59:45 +04:00
struct ieee80211_sta_ht_cap * ht_cap ;
struct ieee80211_sta_vht_cap * vht_cap ;
u32 width , control_freq ;
2012-11-09 02:14:50 +04:00
2012-11-22 19:59:45 +04:00
if ( WARN_ON ( ! cfg80211_chandef_valid ( chandef ) ) )
return false ;
2012-11-09 02:14:50 +04:00
2012-11-22 19:59:45 +04:00
ht_cap = & wiphy - > bands [ chandef - > chan - > band ] - > ht_cap ;
vht_cap = & wiphy - > bands [ chandef - > chan - > band ] - > vht_cap ;
2012-11-09 02:14:50 +04:00
2012-11-22 19:59:45 +04:00
control_freq = chandef - > chan - > center_freq ;
2010-11-13 03:31:23 +03:00
2012-11-09 02:14:50 +04:00
switch ( chandef - > width ) {
2013-05-16 15:00:28 +04:00
case NL80211_CHAN_WIDTH_5 :
width = 5 ;
break ;
case NL80211_CHAN_WIDTH_10 :
width = 10 ;
break ;
2012-11-09 02:14:50 +04:00
case NL80211_CHAN_WIDTH_20 :
2012-11-22 19:59:45 +04:00
if ( ! ht_cap - > ht_supported )
return false ;
case NL80211_CHAN_WIDTH_20_NOHT :
2012-11-09 02:14:50 +04:00
width = 20 ;
break ;
case NL80211_CHAN_WIDTH_40 :
width = 40 ;
2012-11-22 19:59:45 +04:00
if ( ! ht_cap - > ht_supported )
return false ;
if ( ! ( ht_cap - > cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ) | |
ht_cap - > cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT )
return false ;
if ( chandef - > center_freq1 < control_freq & &
chandef - > chan - > flags & IEEE80211_CHAN_NO_HT40MINUS )
return false ;
if ( chandef - > center_freq1 > control_freq & &
chandef - > chan - > flags & IEEE80211_CHAN_NO_HT40PLUS )
return false ;
2012-11-09 02:14:50 +04:00
break ;
case NL80211_CHAN_WIDTH_80P80 :
2012-11-22 19:59:45 +04:00
if ( ! ( vht_cap - > cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ) )
return false ;
case NL80211_CHAN_WIDTH_80 :
if ( ! vht_cap - > vht_supported )
return false ;
2012-12-12 20:50:39 +04:00
prohibited_flags | = IEEE80211_CHAN_NO_80MHZ ;
2012-11-09 02:14:50 +04:00
width = 80 ;
break ;
case NL80211_CHAN_WIDTH_160 :
2012-11-22 19:59:45 +04:00
if ( ! vht_cap - > vht_supported )
return false ;
if ( ! ( vht_cap - > cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ) )
return false ;
2012-12-12 20:50:39 +04:00
prohibited_flags | = IEEE80211_CHAN_NO_160MHZ ;
2012-11-09 02:14:50 +04:00
width = 160 ;
break ;
default :
WARN_ON_ONCE ( 1 ) ;
2010-11-13 03:31:23 +03:00
return false ;
2012-08-27 13:49:39 +04:00
}
2012-11-09 02:14:50 +04:00
2012-12-12 20:50:39 +04:00
/*
* TODO : What if there are only certain 80 / 160 / 80 + 80 MHz channels
* allowed by the driver , or only certain combinations ?
* For 40 MHz the driver can set the NO_HT40 flags , but for
* 80 / 160 MHz and in particular 80 + 80 MHz this isn ' t really
* feasible and we only have NO_80MHZ / NO_160MHZ so far but
* no way to cover 80 + 80 MHz or more complex restrictions .
* Note that such restrictions also need to be advertised to
* userspace , for example for P2P channel selection .
*/
2012-11-22 19:59:45 +04:00
2012-12-04 23:49:42 +04:00
if ( width > 20 )
prohibited_flags | = IEEE80211_CHAN_NO_OFDM ;
2013-05-16 15:00:28 +04:00
/* 5 and 10 MHz are only defined for the OFDM PHY */
if ( width < 20 )
prohibited_flags | = IEEE80211_CHAN_NO_OFDM ;
2012-11-22 19:59:45 +04:00
if ( ! cfg80211_secondary_chans_ok ( wiphy , chandef - > center_freq1 ,
width , prohibited_flags ) )
return false ;
if ( ! chandef - > center_freq2 )
return true ;
return cfg80211_secondary_chans_ok ( wiphy , chandef - > center_freq2 ,
width , prohibited_flags ) ;
}
EXPORT_SYMBOL ( cfg80211_chandef_usable ) ;
bool cfg80211_reg_can_beacon ( struct wiphy * wiphy ,
struct cfg80211_chan_def * chandef )
{
bool res ;
trace_cfg80211_reg_can_beacon ( wiphy , chandef ) ;
2012-11-09 02:14:50 +04:00
2012-11-22 19:59:45 +04:00
res = cfg80211_chandef_usable ( wiphy , chandef ,
IEEE80211_CHAN_DISABLED |
2013-10-21 21:22:25 +04:00
IEEE80211_CHAN_NO_IR |
2012-11-22 19:59:45 +04:00
IEEE80211_CHAN_RADAR ) ;
2012-11-09 02:14:50 +04:00
trace_cfg80211_return_bool ( res ) ;
return res ;
2010-11-13 03:31:23 +03:00
}
2012-11-09 00:25:48 +04:00
EXPORT_SYMBOL ( cfg80211_reg_can_beacon ) ;
2010-11-13 03:31:23 +03:00
2012-06-06 10:18:22 +04:00
int cfg80211_set_monitor_channel ( struct cfg80211_registered_device * rdev ,
2012-11-09 00:25:48 +04:00
struct cfg80211_chan_def * chandef )
2009-12-23 15:15:41 +03:00
{
2012-06-06 10:18:22 +04:00
if ( ! rdev - > ops - > set_monitor_channel )
2009-12-23 15:15:41 +03:00
return - EOPNOTSUPP ;
2012-06-29 14:47:03 +04:00
if ( ! cfg80211_has_monitors_only ( rdev ) )
return - EBUSY ;
2009-12-23 15:15:41 +03:00
2012-11-09 00:25:48 +04:00
return rdev_set_monitor_channel ( rdev , chandef ) ;
2009-08-07 19:22:35 +04:00
}
2012-06-29 14:47:00 +04:00
void
2012-07-10 21:39:02 +04:00
cfg80211_get_chan_state ( struct wireless_dev * wdev ,
2012-06-29 14:47:00 +04:00
struct ieee80211_channel * * chan ,
enum cfg80211_chan_mode * chanmode )
{
* chan = NULL ;
* chanmode = CHAN_MODE_UNDEFINED ;
ASSERT_WDEV_LOCK ( wdev ) ;
2012-06-16 02:19:54 +04:00
if ( wdev - > netdev & & ! netif_running ( wdev - > netdev ) )
2012-06-29 14:47:00 +04:00
return ;
switch ( wdev - > iftype ) {
case NL80211_IFTYPE_ADHOC :
if ( wdev - > current_bss ) {
* chan = wdev - > current_bss - > pub . channel ;
2013-10-07 20:41:05 +04:00
* chanmode = ( wdev - > ibss_fixed & &
! wdev - > ibss_dfs_possible )
2012-06-29 14:47:00 +04:00
? CHAN_MODE_SHARED
: CHAN_MODE_EXCLUSIVE ;
return ;
}
2013-10-25 14:46:44 +04:00
break ;
2012-06-29 14:47:00 +04:00
case NL80211_IFTYPE_STATION :
case NL80211_IFTYPE_P2P_CLIENT :
if ( wdev - > current_bss ) {
* chan = wdev - > current_bss - > pub . channel ;
* chanmode = CHAN_MODE_SHARED ;
return ;
}
break ;
case NL80211_IFTYPE_AP :
case NL80211_IFTYPE_P2P_GO :
2013-02-08 21:16:19 +04:00
if ( wdev - > cac_started ) {
* chan = wdev - > channel ;
* chanmode = CHAN_MODE_SHARED ;
} else if ( wdev - > beacon_interval ) {
2012-07-12 18:10:02 +04:00
* chan = wdev - > channel ;
* chanmode = CHAN_MODE_SHARED ;
}
return ;
2012-06-29 14:47:00 +04:00
case NL80211_IFTYPE_MESH_POINT :
2012-07-12 18:10:02 +04:00
if ( wdev - > mesh_id_len ) {
* chan = wdev - > channel ;
* chanmode = CHAN_MODE_SHARED ;
}
2012-06-29 14:47:00 +04:00
return ;
case NL80211_IFTYPE_MONITOR :
case NL80211_IFTYPE_AP_VLAN :
case NL80211_IFTYPE_WDS :
/* these interface types don't really have a channel */
return ;
2012-06-16 02:19:54 +04:00
case NL80211_IFTYPE_P2P_DEVICE :
if ( wdev - > wiphy - > features &
NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL )
* chanmode = CHAN_MODE_EXCLUSIVE ;
return ;
2012-06-29 14:47:00 +04:00
case NL80211_IFTYPE_UNSPECIFIED :
case NUM_NL80211_IFTYPES :
WARN_ON ( 1 ) ;
}
return ;
}