18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/ieee80211.h> 38c2ecf20Sopenharmony_ci#include <linux/export.h> 48c2ecf20Sopenharmony_ci#include <net/cfg80211.h> 58c2ecf20Sopenharmony_ci#include "nl80211.h" 68c2ecf20Sopenharmony_ci#include "core.h" 78c2ecf20Sopenharmony_ci#include "rdev-ops.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* Default values, timeouts in ms */ 108c2ecf20Sopenharmony_ci#define MESH_TTL 31 118c2ecf20Sopenharmony_ci#define MESH_DEFAULT_ELEMENT_TTL 31 128c2ecf20Sopenharmony_ci#define MESH_MAX_RETR 3 138c2ecf20Sopenharmony_ci#define MESH_RET_T 100 148c2ecf20Sopenharmony_ci#define MESH_CONF_T 100 158c2ecf20Sopenharmony_ci#define MESH_HOLD_T 100 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define MESH_PATH_TIMEOUT 5000 188c2ecf20Sopenharmony_ci#define MESH_RANN_INTERVAL 5000 198c2ecf20Sopenharmony_ci#define MESH_PATH_TO_ROOT_TIMEOUT 6000 208c2ecf20Sopenharmony_ci#define MESH_ROOT_INTERVAL 5000 218c2ecf20Sopenharmony_ci#define MESH_ROOT_CONFIRMATION_INTERVAL 2000 228c2ecf20Sopenharmony_ci#define MESH_DEFAULT_PLINK_TIMEOUT 1800 /* timeout in seconds */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * Minimum interval between two consecutive PREQs originated by the same 268c2ecf20Sopenharmony_ci * interface 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci#define MESH_PREQ_MIN_INT 10 298c2ecf20Sopenharmony_ci#define MESH_PERR_MIN_INT 100 308c2ecf20Sopenharmony_ci#define MESH_DIAM_TRAVERSAL_TIME 50 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define MESH_RSSI_THRESHOLD 0 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds 368c2ecf20Sopenharmony_ci * before timing out. This way it will remain ACTIVE and no data frames 378c2ecf20Sopenharmony_ci * will be unnecessarily held in the pending queue. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci#define MESH_PATH_REFRESH_TIME 1000 408c2ecf20Sopenharmony_ci#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Default maximum number of established plinks per interface */ 438c2ecf20Sopenharmony_ci#define MESH_MAX_ESTAB_PLINKS 32 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define MESH_MAX_PREQ_RETRIES 4 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define MESH_SYNC_NEIGHBOR_OFFSET_MAX 50 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units (=TUs) */ 508c2ecf20Sopenharmony_ci#define MESH_DEFAULT_DTIM_PERIOD 2 518c2ecf20Sopenharmony_ci#define MESH_DEFAULT_AWAKE_WINDOW 10 /* in 1024 us units (=TUs) */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciconst struct mesh_config default_mesh_config = { 548c2ecf20Sopenharmony_ci .dot11MeshRetryTimeout = MESH_RET_T, 558c2ecf20Sopenharmony_ci .dot11MeshConfirmTimeout = MESH_CONF_T, 568c2ecf20Sopenharmony_ci .dot11MeshHoldingTimeout = MESH_HOLD_T, 578c2ecf20Sopenharmony_ci .dot11MeshMaxRetries = MESH_MAX_RETR, 588c2ecf20Sopenharmony_ci .dot11MeshTTL = MESH_TTL, 598c2ecf20Sopenharmony_ci .element_ttl = MESH_DEFAULT_ELEMENT_TTL, 608c2ecf20Sopenharmony_ci .auto_open_plinks = true, 618c2ecf20Sopenharmony_ci .dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS, 628c2ecf20Sopenharmony_ci .dot11MeshNbrOffsetMaxNeighbor = MESH_SYNC_NEIGHBOR_OFFSET_MAX, 638c2ecf20Sopenharmony_ci .dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT, 648c2ecf20Sopenharmony_ci .dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT, 658c2ecf20Sopenharmony_ci .dot11MeshHWMPperrMinInterval = MESH_PERR_MIN_INT, 668c2ecf20Sopenharmony_ci .dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME, 678c2ecf20Sopenharmony_ci .dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES, 688c2ecf20Sopenharmony_ci .path_refresh_time = MESH_PATH_REFRESH_TIME, 698c2ecf20Sopenharmony_ci .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT, 708c2ecf20Sopenharmony_ci .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL, 718c2ecf20Sopenharmony_ci .dot11MeshGateAnnouncementProtocol = false, 728c2ecf20Sopenharmony_ci .dot11MeshForwarding = true, 738c2ecf20Sopenharmony_ci .rssi_threshold = MESH_RSSI_THRESHOLD, 748c2ecf20Sopenharmony_ci .ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED, 758c2ecf20Sopenharmony_ci .dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT, 768c2ecf20Sopenharmony_ci .dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL, 778c2ecf20Sopenharmony_ci .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL, 788c2ecf20Sopenharmony_ci .power_mode = NL80211_MESH_POWER_ACTIVE, 798c2ecf20Sopenharmony_ci .dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW, 808c2ecf20Sopenharmony_ci .plink_timeout = MESH_DEFAULT_PLINK_TIMEOUT, 818c2ecf20Sopenharmony_ci .dot11MeshNolearn = false, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciconst struct mesh_setup default_mesh_setup = { 858c2ecf20Sopenharmony_ci /* cfg80211_join_mesh() will pick a channel if needed */ 868c2ecf20Sopenharmony_ci .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, 878c2ecf20Sopenharmony_ci .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, 888c2ecf20Sopenharmony_ci .path_metric = IEEE80211_PATH_METRIC_AIRTIME, 898c2ecf20Sopenharmony_ci .auth_id = 0, /* open */ 908c2ecf20Sopenharmony_ci .ie = NULL, 918c2ecf20Sopenharmony_ci .ie_len = 0, 928c2ecf20Sopenharmony_ci .is_secure = false, 938c2ecf20Sopenharmony_ci .user_mpm = false, 948c2ecf20Sopenharmony_ci .beacon_interval = MESH_DEFAULT_BEACON_INTERVAL, 958c2ecf20Sopenharmony_ci .dtim_period = MESH_DEFAULT_DTIM_PERIOD, 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ciint __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, 998c2ecf20Sopenharmony_ci struct net_device *dev, 1008c2ecf20Sopenharmony_ci struct mesh_setup *setup, 1018c2ecf20Sopenharmony_ci const struct mesh_config *conf) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 1048c2ecf20Sopenharmony_ci int err; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci ASSERT_WDEV_LOCK(wdev); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) 1118c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!(rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && 1148c2ecf20Sopenharmony_ci setup->is_secure) 1158c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (wdev->mesh_id_len) 1188c2ecf20Sopenharmony_ci return -EALREADY; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (!setup->mesh_id_len) 1218c2ecf20Sopenharmony_ci return -EINVAL; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!rdev->ops->join_mesh) 1248c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (!setup->chandef.chan) { 1278c2ecf20Sopenharmony_ci /* if no channel explicitly given, use preset channel */ 1288c2ecf20Sopenharmony_ci setup->chandef = wdev->preset_chandef; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (!setup->chandef.chan) { 1328c2ecf20Sopenharmony_ci /* if we don't have that either, use the first usable channel */ 1338c2ecf20Sopenharmony_ci enum nl80211_band band; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 1368c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 1378c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 1388c2ecf20Sopenharmony_ci int i; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci sband = rdev->wiphy.bands[band]; 1418c2ecf20Sopenharmony_ci if (!sband) 1428c2ecf20Sopenharmony_ci continue; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 1458c2ecf20Sopenharmony_ci chan = &sband->channels[i]; 1468c2ecf20Sopenharmony_ci if (chan->flags & (IEEE80211_CHAN_NO_IR | 1478c2ecf20Sopenharmony_ci IEEE80211_CHAN_DISABLED | 1488c2ecf20Sopenharmony_ci IEEE80211_CHAN_RADAR)) 1498c2ecf20Sopenharmony_ci continue; 1508c2ecf20Sopenharmony_ci setup->chandef.chan = chan; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (setup->chandef.chan) 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* no usable channel ... */ 1598c2ecf20Sopenharmony_ci if (!setup->chandef.chan) 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT; 1638c2ecf20Sopenharmony_ci setup->chandef.center_freq1 = setup->chandef.chan->center_freq; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* 1678c2ecf20Sopenharmony_ci * check if basic rates are available otherwise use mandatory rates as 1688c2ecf20Sopenharmony_ci * basic rates 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci if (!setup->basic_rates) { 1718c2ecf20Sopenharmony_ci enum nl80211_bss_scan_width scan_width; 1728c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband = 1738c2ecf20Sopenharmony_ci rdev->wiphy.bands[setup->chandef.chan->band]; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (setup->chandef.chan->band == NL80211_BAND_2GHZ) { 1768c2ecf20Sopenharmony_ci int i; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* 1798c2ecf20Sopenharmony_ci * Older versions selected the mandatory rates for 1808c2ecf20Sopenharmony_ci * 2.4 GHz as well, but were broken in that only 1818c2ecf20Sopenharmony_ci * 1 Mbps was regarded as a mandatory rate. Keep 1828c2ecf20Sopenharmony_ci * using just 1 Mbps as the default basic rate for 1838c2ecf20Sopenharmony_ci * mesh to be interoperable with older versions. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_bitrates; i++) { 1868c2ecf20Sopenharmony_ci if (sband->bitrates[i].bitrate == 10) { 1878c2ecf20Sopenharmony_ci setup->basic_rates = BIT(i); 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci } else { 1928c2ecf20Sopenharmony_ci scan_width = cfg80211_chandef_to_scan_width(&setup->chandef); 1938c2ecf20Sopenharmony_ci setup->basic_rates = ieee80211_mandatory_rates(sband, 1948c2ecf20Sopenharmony_ci scan_width); 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci err = cfg80211_chandef_dfs_required(&rdev->wiphy, 1998c2ecf20Sopenharmony_ci &setup->chandef, 2008c2ecf20Sopenharmony_ci NL80211_IFTYPE_MESH_POINT); 2018c2ecf20Sopenharmony_ci if (err < 0) 2028c2ecf20Sopenharmony_ci return err; 2038c2ecf20Sopenharmony_ci if (err > 0 && !setup->userspace_handles_dfs) 2048c2ecf20Sopenharmony_ci return -EINVAL; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef, 2078c2ecf20Sopenharmony_ci NL80211_IFTYPE_MESH_POINT)) 2088c2ecf20Sopenharmony_ci return -EINVAL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci err = rdev_join_mesh(rdev, dev, conf, setup); 2118c2ecf20Sopenharmony_ci if (!err) { 2128c2ecf20Sopenharmony_ci memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); 2138c2ecf20Sopenharmony_ci wdev->mesh_id_len = setup->mesh_id_len; 2148c2ecf20Sopenharmony_ci wdev->chandef = setup->chandef; 2158c2ecf20Sopenharmony_ci wdev->beacon_interval = setup->beacon_interval; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return err; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ciint cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, 2228c2ecf20Sopenharmony_ci struct wireless_dev *wdev, 2238c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci int err; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * Workaround for libertas (only!), it puts the interface 2298c2ecf20Sopenharmony_ci * into mesh mode but doesn't implement join_mesh. Instead, 2308c2ecf20Sopenharmony_ci * it is configured via sysfs and then joins the mesh when 2318c2ecf20Sopenharmony_ci * you set the channel. Note that the libertas mesh isn't 2328c2ecf20Sopenharmony_ci * compatible with 802.11 mesh. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci if (rdev->ops->libertas_set_mesh_channel) { 2358c2ecf20Sopenharmony_ci if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT) 2368c2ecf20Sopenharmony_ci return -EINVAL; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (!netif_running(wdev->netdev)) 2398c2ecf20Sopenharmony_ci return -ENETDOWN; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, 2428c2ecf20Sopenharmony_ci chandef->chan); 2438c2ecf20Sopenharmony_ci if (!err) 2448c2ecf20Sopenharmony_ci wdev->chandef = *chandef; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return err; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (wdev->mesh_id_len) 2508c2ecf20Sopenharmony_ci return -EBUSY; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci wdev->preset_chandef = *chandef; 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciint __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, 2578c2ecf20Sopenharmony_ci struct net_device *dev) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 2608c2ecf20Sopenharmony_ci int err; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci ASSERT_WDEV_LOCK(wdev); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) 2658c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (!rdev->ops->leave_mesh) 2688c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (!wdev->mesh_id_len) 2718c2ecf20Sopenharmony_ci return -ENOTCONN; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci err = rdev_leave_mesh(rdev, dev); 2748c2ecf20Sopenharmony_ci if (!err) { 2758c2ecf20Sopenharmony_ci wdev->conn_owner_nlportid = 0; 2768c2ecf20Sopenharmony_ci wdev->mesh_id_len = 0; 2778c2ecf20Sopenharmony_ci wdev->beacon_interval = 0; 2788c2ecf20Sopenharmony_ci memset(&wdev->chandef, 0, sizeof(wdev->chandef)); 2798c2ecf20Sopenharmony_ci rdev_set_qos_map(rdev, dev, NULL); 2808c2ecf20Sopenharmony_ci cfg80211_sched_dfs_chan_update(rdev); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return err; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ciint cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, 2878c2ecf20Sopenharmony_ci struct net_device *dev) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 2908c2ecf20Sopenharmony_ci int err; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci wdev_lock(wdev); 2938c2ecf20Sopenharmony_ci err = __cfg80211_leave_mesh(rdev, dev); 2948c2ecf20Sopenharmony_ci wdev_unlock(wdev); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return err; 2978c2ecf20Sopenharmony_ci} 298