2009-08-07 17:22:35 +02: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 16:56:32 +01:00
# include <linux/export.h>
2009-08-07 17:22:35 +02:00
# include <net/cfg80211.h>
# include "core.h"
2009-12-23 13:15:41 +01:00
struct ieee80211_channel *
rdev_freq_to_chan ( struct cfg80211_registered_device * rdev ,
2009-08-07 17:22:35 +02:00
int freq , enum nl80211_channel_type channel_type )
{
struct ieee80211_channel * chan ;
struct ieee80211_sta_ht_cap * ht_cap ;
chan = ieee80211_get_channel ( & rdev - > wiphy , freq ) ;
/* Primary channel not allowed */
if ( ! chan | | chan - > flags & IEEE80211_CHAN_DISABLED )
2009-12-23 13:15:41 +01:00
return NULL ;
2009-08-07 17:22:35 +02:00
if ( channel_type = = NL80211_CHAN_HT40MINUS & &
chan - > flags & IEEE80211_CHAN_NO_HT40MINUS )
2009-12-23 13:15:41 +01:00
return NULL ;
2009-08-07 17:22:35 +02:00
else if ( channel_type = = NL80211_CHAN_HT40PLUS & &
chan - > flags & IEEE80211_CHAN_NO_HT40PLUS )
2009-12-23 13:15:41 +01:00
return NULL ;
2009-08-07 17:22:35 +02:00
ht_cap = & rdev - > wiphy . bands [ chan - > band ] - > ht_cap ;
if ( channel_type ! = NL80211_CHAN_NO_HT ) {
if ( ! ht_cap - > ht_supported )
2009-12-23 13:15:41 +01:00
return NULL ;
2009-08-07 17:22:35 +02:00
2010-05-17 17:30:59 +02:00
if ( channel_type ! = NL80211_CHAN_HT20 & &
( ! ( ht_cap - > cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ) | |
ht_cap - > cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT ) )
2009-12-23 13:15:41 +01:00
return NULL ;
2009-08-07 17:22:35 +02:00
}
2009-12-23 13:15:41 +01:00
return chan ;
}
2012-05-10 21:25:23 +02:00
bool cfg80211_can_beacon_sec_chan ( struct wiphy * wiphy ,
2011-11-30 16:56:32 +01:00
struct ieee80211_channel * chan ,
enum nl80211_channel_type channel_type )
2010-11-12 16:31:23 -08:00
{
struct ieee80211_channel * sec_chan ;
int diff ;
switch ( channel_type ) {
case NL80211_CHAN_HT40PLUS :
diff = 20 ;
2010-11-17 16:34:37 -05:00
break ;
2010-11-12 16:31:23 -08:00
case NL80211_CHAN_HT40MINUS :
diff = - 20 ;
2010-11-17 16:34:37 -05:00
break ;
2010-11-12 16:31:23 -08:00
default :
2012-05-16 23:50:17 +02:00
return true ;
2010-11-12 16:31:23 -08:00
}
sec_chan = ieee80211_get_channel ( wiphy , chan - > center_freq + diff ) ;
if ( ! sec_chan )
return false ;
/* we'll need a DFS capability later */
if ( sec_chan - > flags & ( IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_PASSIVE_SCAN |
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_RADAR ) )
return false ;
return true ;
}
2011-11-30 16:56:32 +01:00
EXPORT_SYMBOL ( cfg80211_can_beacon_sec_chan ) ;
2010-11-12 16:31:23 -08:00
2012-06-06 08:18:22 +02:00
int cfg80211_set_monitor_channel ( struct cfg80211_registered_device * rdev ,
int freq , enum nl80211_channel_type chantype )
2009-12-23 13:15:41 +01:00
{
struct ieee80211_channel * chan ;
2012-06-06 08:18:22 +02:00
if ( ! rdev - > ops - > set_monitor_channel )
2009-12-23 13:15:41 +01:00
return - EOPNOTSUPP ;
2012-06-29 12:47:03 +02:00
if ( ! cfg80211_has_monitors_only ( rdev ) )
return - EBUSY ;
2009-12-23 13:15:41 +01:00
2012-06-06 08:18:22 +02:00
chan = rdev_freq_to_chan ( rdev , freq , chantype ) ;
2009-12-23 13:15:41 +01:00
if ( ! chan )
return - EINVAL ;
2012-07-12 22:19:48 +02:00
return rdev - > ops - > set_monitor_channel ( & rdev - > wiphy , chan , chantype ) ;
2009-08-07 17:22:35 +02:00
}
2012-06-29 12:47:00 +02:00
void
2012-07-10 19:39:02 +02:00
cfg80211_get_chan_state ( struct wireless_dev * wdev ,
2012-06-29 12:47:00 +02:00
struct ieee80211_channel * * chan ,
enum cfg80211_chan_mode * chanmode )
{
* chan = NULL ;
* chanmode = CHAN_MODE_UNDEFINED ;
ASSERT_WDEV_LOCK ( wdev ) ;
if ( ! netif_running ( wdev - > netdev ) )
return ;
switch ( wdev - > iftype ) {
case NL80211_IFTYPE_ADHOC :
if ( wdev - > current_bss ) {
* chan = wdev - > current_bss - > pub . channel ;
* chanmode = wdev - > ibss_fixed
? CHAN_MODE_SHARED
: CHAN_MODE_EXCLUSIVE ;
return ;
}
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 :
2012-07-12 16:10:02 +02:00
if ( wdev - > beacon_interval ) {
* chan = wdev - > channel ;
* chanmode = CHAN_MODE_SHARED ;
}
return ;
2012-06-29 12:47:00 +02:00
case NL80211_IFTYPE_MESH_POINT :
2012-07-12 16:10:02 +02:00
if ( wdev - > mesh_id_len ) {
* chan = wdev - > channel ;
* chanmode = CHAN_MODE_SHARED ;
}
2012-06-29 12:47:00 +02: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 ;
case NL80211_IFTYPE_UNSPECIFIED :
case NUM_NL80211_IFTYPES :
WARN_ON ( 1 ) ;
}
return ;
}