2010-12-03 11:20:44 +03:00
# include <linux/ieee80211.h>
2011-07-15 19:47:34 +04:00
# include <linux/export.h>
2010-12-03 11:20:44 +03:00
# include <net/cfg80211.h>
2011-04-08 02:08:34 +04:00
# include "nl80211.h"
2010-12-03 11:20:44 +03:00
# include "core.h"
2012-06-27 18:19:42 +04:00
# include "rdev-ops.h"
2010-12-03 11:20:44 +03:00
/* Default values, timeouts in ms */
# define MESH_TTL 31
# define MESH_DEFAULT_ELEMENT_TTL 31
# define MESH_MAX_RETR 3
# define MESH_RET_T 100
# define MESH_CONF_T 100
# define MESH_HOLD_T 100
# define MESH_PATH_TIMEOUT 5000
2011-08-10 03:45:10 +04:00
# define MESH_RANN_INTERVAL 5000
2012-06-13 22:06:06 +04:00
# define MESH_PATH_TO_ROOT_TIMEOUT 6000
# define MESH_ROOT_INTERVAL 5000
2012-06-13 22:06:10 +04:00
# define MESH_ROOT_CONFIRMATION_INTERVAL 2000
2013-06-03 20:53:39 +04:00
# define MESH_DEFAULT_PLINK_TIMEOUT 1800 /* timeout in seconds */
2010-12-03 11:20:44 +03:00
/*
* Minimum interval between two consecutive PREQs originated by the same
* interface
*/
# define MESH_PREQ_MIN_INT 10
2011-11-25 05:15:24 +04:00
# define MESH_PERR_MIN_INT 100
2010-12-03 11:20:44 +03:00
# define MESH_DIAM_TRAVERSAL_TIME 50
2012-02-29 05:04:08 +04:00
# define MESH_RSSI_THRESHOLD 0
2010-12-03 11:20:44 +03:00
/*
* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds
* before timing out . This way it will remain ACTIVE and no data frames
* will be unnecessarily held in the pending queue .
*/
# define MESH_PATH_REFRESH_TIME 1000
# define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
/* Default maximum number of established plinks per interface */
# define MESH_MAX_ESTAB_PLINKS 32
# define MESH_MAX_PREQ_RETRIES 4
2012-03-31 22:31:33 +04:00
# define MESH_SYNC_NEIGHBOR_OFFSET_MAX 50
2010-12-03 11:20:44 +03:00
2013-01-07 19:04:51 +04:00
# define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units (=TUs) */
# define MESH_DEFAULT_DTIM_PERIOD 2
2013-01-07 19:04:52 +04:00
# define MESH_DEFAULT_AWAKE_WINDOW 10 /* in 1024 us units (=TUs) */
2013-01-07 19:04:51 +04:00
2010-12-03 11:20:44 +03:00
const struct mesh_config default_mesh_config = {
. dot11MeshRetryTimeout = MESH_RET_T ,
. dot11MeshConfirmTimeout = MESH_CONF_T ,
. dot11MeshHoldingTimeout = MESH_HOLD_T ,
. dot11MeshMaxRetries = MESH_MAX_RETR ,
. dot11MeshTTL = MESH_TTL ,
. element_ttl = MESH_DEFAULT_ELEMENT_TTL ,
. auto_open_plinks = true ,
. dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS ,
2012-03-31 22:31:33 +04:00
. dot11MeshNbrOffsetMaxNeighbor = MESH_SYNC_NEIGHBOR_OFFSET_MAX ,
2010-12-03 11:20:44 +03:00
. dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT ,
. dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT ,
2011-11-25 05:15:24 +04:00
. dot11MeshHWMPperrMinInterval = MESH_PERR_MIN_INT ,
2010-12-03 11:20:44 +03:00
. dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME ,
. dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES ,
. path_refresh_time = MESH_PATH_REFRESH_TIME ,
. min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT ,
2011-08-10 03:45:10 +04:00
. dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL ,
2011-08-10 03:45:11 +04:00
. dot11MeshGateAnnouncementProtocol = false ,
2012-01-20 21:02:16 +04:00
. dot11MeshForwarding = true ,
2012-02-29 05:04:08 +04:00
. rssi_threshold = MESH_RSSI_THRESHOLD ,
2012-05-01 01:20:32 +04:00
. ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED ,
2012-06-13 22:06:06 +04:00
. dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT ,
. dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL ,
2012-06-13 22:06:10 +04:00
. dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL ,
2013-01-07 19:04:52 +04:00
. power_mode = NL80211_MESH_POWER_ACTIVE ,
. dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW ,
2013-06-03 20:53:39 +04:00
. plink_timeout = MESH_DEFAULT_PLINK_TIMEOUT ,
2010-12-03 11:20:44 +03:00
} ;
2010-12-17 04:37:49 +03:00
const struct mesh_setup default_mesh_setup = {
2012-05-17 01:50:20 +04:00
/* cfg80211_join_mesh() will pick a channel if needed */
2012-03-31 22:31:33 +04:00
. sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET ,
2010-12-17 04:37:49 +03:00
. path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP ,
. path_metric = IEEE80211_PATH_METRIC_AIRTIME ,
2013-05-08 22:45:59 +04:00
. auth_id = 0 , /* open */
2011-04-08 02:08:27 +04:00
. ie = NULL ,
. ie_len = 0 ,
2011-04-08 02:08:29 +04:00
. is_secure = false ,
2013-03-05 01:06:10 +04:00
. user_mpm = false ,
2013-01-07 19:04:51 +04:00
. beacon_interval = MESH_DEFAULT_BEACON_INTERVAL ,
. dtim_period = MESH_DEFAULT_DTIM_PERIOD ,
2010-12-17 04:37:49 +03:00
} ;
2010-12-03 11:20:44 +03:00
int __cfg80211_join_mesh ( struct cfg80211_registered_device * rdev ,
struct net_device * dev ,
2012-05-17 01:50:20 +04:00
struct mesh_setup * setup ,
2010-12-03 11:20:44 +03:00
const struct mesh_config * conf )
{
struct wireless_dev * wdev = dev - > ieee80211_ptr ;
int err ;
BUILD_BUG_ON ( IEEE80211_MAX_SSID_LEN ! = IEEE80211_MAX_MESH_ID_LEN ) ;
ASSERT_WDEV_LOCK ( wdev ) ;
if ( dev - > ieee80211_ptr - > iftype ! = NL80211_IFTYPE_MESH_POINT )
return - EOPNOTSUPP ;
2011-04-08 02:08:28 +04:00
if ( ! ( rdev - > wiphy . flags & WIPHY_FLAG_MESH_AUTH ) & &
setup - > is_secure )
return - EOPNOTSUPP ;
2010-12-03 11:20:44 +03:00
if ( wdev - > mesh_id_len )
return - EALREADY ;
2010-12-17 04:37:49 +03:00
if ( ! setup - > mesh_id_len )
2010-12-03 11:20:44 +03:00
return - EINVAL ;
if ( ! rdev - > ops - > join_mesh )
return - EOPNOTSUPP ;
2012-11-09 00:25:48 +04:00
if ( ! setup - > chandef . chan ) {
2012-05-17 01:50:20 +04:00
/* if no channel explicitly given, use preset channel */
2012-11-09 00:25:48 +04:00
setup - > chandef = wdev - > preset_chandef ;
2012-05-17 01:50:20 +04:00
}
2012-11-09 00:25:48 +04:00
if ( ! setup - > chandef . chan ) {
2012-05-17 01:50:20 +04:00
/* if we don't have that either, use the first usable channel */
enum ieee80211_band band ;
for ( band = 0 ; band < IEEE80211_NUM_BANDS ; band + + ) {
struct ieee80211_supported_band * sband ;
struct ieee80211_channel * chan ;
int i ;
sband = rdev - > wiphy . bands [ band ] ;
if ( ! sband )
continue ;
for ( i = 0 ; i < sband - > n_channels ; i + + ) {
chan = & sband - > channels [ i ] ;
2013-10-21 21:22:25 +04:00
if ( chan - > flags & ( IEEE80211_CHAN_NO_IR |
2012-05-17 01:50:20 +04:00
IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_RADAR ) )
continue ;
2012-11-09 00:25:48 +04:00
setup - > chandef . chan = chan ;
2012-05-17 01:50:20 +04:00
break ;
}
2012-11-09 00:25:48 +04:00
if ( setup - > chandef . chan )
2012-05-17 01:50:20 +04:00
break ;
}
/* no usable channel ... */
2012-11-09 00:25:48 +04:00
if ( ! setup - > chandef . chan )
2012-05-17 01:50:20 +04:00
return - EINVAL ;
2012-12-03 14:23:37 +04:00
setup - > chandef . width = NL80211_CHAN_WIDTH_20_NOHT ;
setup - > chandef . center_freq1 = setup - > chandef . chan - > center_freq ;
2012-05-17 01:50:20 +04:00
}
2013-06-03 21:33:36 +04:00
/*
* check if basic rates are available otherwise use mandatory rates as
* basic rates
*/
if ( ! setup - > basic_rates ) {
2013-07-08 18:55:54 +04:00
enum nl80211_bss_scan_width scan_width ;
2013-06-03 21:33:36 +04:00
struct ieee80211_supported_band * sband =
rdev - > wiphy . bands [ setup - > chandef . chan - > band ] ;
2013-07-08 18:55:54 +04:00
scan_width = cfg80211_chandef_to_scan_width ( & setup - > chandef ) ;
setup - > basic_rates = ieee80211_mandatory_rates ( sband ,
scan_width ) ;
2013-06-03 21:33:36 +04:00
}
2014-02-23 11:13:01 +04:00
if ( ! cfg80211_reg_can_beacon ( & rdev - > wiphy , & setup - > chandef ,
NL80211_IFTYPE_MESH_POINT ) )
2012-05-17 01:50:20 +04:00
return - EINVAL ;
2012-06-27 18:19:42 +04:00
err = rdev_join_mesh ( rdev , dev , conf , setup ) ;
2010-12-03 11:20:44 +03:00
if ( ! err ) {
2010-12-17 04:37:49 +03:00
memcpy ( wdev - > ssid , setup - > mesh_id , setup - > mesh_id_len ) ;
wdev - > mesh_id_len = setup - > mesh_id_len ;
2014-01-29 17:22:27 +04:00
wdev - > chandef = setup - > chandef ;
2010-12-03 11:20:44 +03:00
}
return err ;
}
int cfg80211_join_mesh ( struct cfg80211_registered_device * rdev ,
struct net_device * dev ,
2012-05-17 01:50:20 +04:00
struct mesh_setup * setup ,
2010-12-03 11:20:44 +03:00
const struct mesh_config * conf )
{
struct wireless_dev * wdev = dev - > ieee80211_ptr ;
int err ;
wdev_lock ( wdev ) ;
2010-12-17 04:37:49 +03:00
err = __cfg80211_join_mesh ( rdev , dev , setup , conf ) ;
2010-12-03 11:20:44 +03:00
wdev_unlock ( wdev ) ;
return err ;
}
2012-11-09 00:25:48 +04:00
int cfg80211_set_mesh_channel ( struct cfg80211_registered_device * rdev ,
struct wireless_dev * wdev ,
struct cfg80211_chan_def * chandef )
2012-05-17 01:50:20 +04:00
{
2012-06-29 14:46:58 +04:00
int err ;
2012-05-17 01:50:20 +04:00
/*
* Workaround for libertas ( only ! ) , it puts the interface
* into mesh mode but doesn ' t implement join_mesh . Instead ,
* it is configured via sysfs and then joins the mesh when
* you set the channel . Note that the libertas mesh isn ' t
* compatible with 802.11 mesh .
*/
2012-06-06 10:18:22 +04:00
if ( rdev - > ops - > libertas_set_mesh_channel ) {
2012-11-09 02:14:50 +04:00
if ( chandef - > width ! = NL80211_CHAN_WIDTH_20_NOHT )
2012-06-06 10:18:22 +04:00
return - EINVAL ;
2012-05-17 01:50:20 +04:00
if ( ! netif_running ( wdev - > netdev ) )
return - ENETDOWN ;
2012-06-29 14:46:58 +04:00
2012-06-27 18:19:42 +04:00
err = rdev_libertas_set_mesh_channel ( rdev , wdev - > netdev ,
2012-11-09 00:25:48 +04:00
chandef - > chan ) ;
2012-06-29 14:46:58 +04:00
if ( ! err )
2014-01-29 17:22:27 +04:00
wdev - > chandef = * chandef ;
2012-06-29 14:46:58 +04:00
return err ;
2012-05-17 01:50:20 +04:00
}
if ( wdev - > mesh_id_len )
return - EBUSY ;
2012-11-09 00:25:48 +04:00
wdev - > preset_chandef = * chandef ;
2012-05-17 01:50:20 +04:00
return 0 ;
}
2010-12-03 11:20:44 +03:00
static int __cfg80211_leave_mesh ( struct cfg80211_registered_device * rdev ,
struct net_device * dev )
{
struct wireless_dev * wdev = dev - > ieee80211_ptr ;
int err ;
ASSERT_WDEV_LOCK ( wdev ) ;
if ( dev - > ieee80211_ptr - > iftype ! = NL80211_IFTYPE_MESH_POINT )
return - EOPNOTSUPP ;
if ( ! rdev - > ops - > leave_mesh )
return - EOPNOTSUPP ;
if ( ! wdev - > mesh_id_len )
return - ENOTCONN ;
2012-06-27 18:19:42 +04:00
err = rdev_leave_mesh ( rdev , dev ) ;
2012-06-29 14:46:58 +04:00
if ( ! err ) {
2010-12-03 11:20:44 +03:00
wdev - > mesh_id_len = 0 ;
2014-01-29 17:22:27 +04:00
memset ( & wdev - > chandef , 0 , sizeof ( wdev - > chandef ) ) ;
2013-12-17 11:01:30 +04:00
rdev_set_qos_map ( rdev , dev , NULL ) ;
2012-06-29 14:46:58 +04:00
}
2010-12-03 11:20:44 +03:00
return err ;
}
int cfg80211_leave_mesh ( struct cfg80211_registered_device * rdev ,
struct net_device * dev )
{
struct wireless_dev * wdev = dev - > ieee80211_ptr ;
int err ;
wdev_lock ( wdev ) ;
err = __cfg80211_leave_mesh ( rdev , dev ) ;
wdev_unlock ( wdev ) ;
return err ;
}