1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Portions |
4 | * Copyright (C) 2022-2023 Intel Corporation |
5 | */ |
6 | #include <linux/ieee80211.h> |
7 | #include <linux/export.h> |
8 | #include <net/cfg80211.h> |
9 | #include "nl80211.h" |
10 | #include "core.h" |
11 | #include "rdev-ops.h" |
12 | |
13 | /* Default values, timeouts in ms */ |
14 | #define MESH_TTL 31 |
15 | #define MESH_DEFAULT_ELEMENT_TTL 31 |
16 | #define MESH_MAX_RETR 3 |
17 | #define MESH_RET_T 100 |
18 | #define MESH_CONF_T 100 |
19 | #define MESH_HOLD_T 100 |
20 | |
21 | #define MESH_PATH_TIMEOUT 5000 |
22 | #define MESH_RANN_INTERVAL 5000 |
23 | #define MESH_PATH_TO_ROOT_TIMEOUT 6000 |
24 | #define MESH_ROOT_INTERVAL 5000 |
25 | #define MESH_ROOT_CONFIRMATION_INTERVAL 2000 |
26 | #define MESH_DEFAULT_PLINK_TIMEOUT 1800 /* timeout in seconds */ |
27 | |
28 | /* |
29 | * Minimum interval between two consecutive PREQs originated by the same |
30 | * interface |
31 | */ |
32 | #define MESH_PREQ_MIN_INT 10 |
33 | #define MESH_PERR_MIN_INT 100 |
34 | #define MESH_DIAM_TRAVERSAL_TIME 50 |
35 | |
36 | #define 0 |
37 | |
38 | /* |
39 | * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds |
40 | * before timing out. This way it will remain ACTIVE and no data frames |
41 | * will be unnecessarily held in the pending queue. |
42 | */ |
43 | #define MESH_PATH_REFRESH_TIME 1000 |
44 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) |
45 | |
46 | /* Default maximum number of established plinks per interface */ |
47 | #define MESH_MAX_ESTAB_PLINKS 32 |
48 | |
49 | #define MESH_MAX_PREQ_RETRIES 4 |
50 | |
51 | #define MESH_SYNC_NEIGHBOR_OFFSET_MAX 50 |
52 | |
53 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units (=TUs) */ |
54 | #define MESH_DEFAULT_DTIM_PERIOD 2 |
55 | #define MESH_DEFAULT_AWAKE_WINDOW 10 /* in 1024 us units (=TUs) */ |
56 | |
57 | const struct mesh_config default_mesh_config = { |
58 | .dot11MeshRetryTimeout = MESH_RET_T, |
59 | .dot11MeshConfirmTimeout = MESH_CONF_T, |
60 | .dot11MeshHoldingTimeout = MESH_HOLD_T, |
61 | .dot11MeshMaxRetries = MESH_MAX_RETR, |
62 | .dot11MeshTTL = MESH_TTL, |
63 | .element_ttl = MESH_DEFAULT_ELEMENT_TTL, |
64 | .auto_open_plinks = true, |
65 | .dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS, |
66 | .dot11MeshNbrOffsetMaxNeighbor = MESH_SYNC_NEIGHBOR_OFFSET_MAX, |
67 | .dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT, |
68 | .dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT, |
69 | .dot11MeshHWMPperrMinInterval = MESH_PERR_MIN_INT, |
70 | .dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME, |
71 | .dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES, |
72 | .path_refresh_time = MESH_PATH_REFRESH_TIME, |
73 | .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT, |
74 | .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL, |
75 | .dot11MeshGateAnnouncementProtocol = false, |
76 | .dot11MeshForwarding = true, |
77 | .rssi_threshold = MESH_RSSI_THRESHOLD, |
78 | .ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED, |
79 | .dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT, |
80 | .dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL, |
81 | .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL, |
82 | .power_mode = NL80211_MESH_POWER_ACTIVE, |
83 | .dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW, |
84 | .plink_timeout = MESH_DEFAULT_PLINK_TIMEOUT, |
85 | .dot11MeshNolearn = false, |
86 | }; |
87 | |
88 | const struct mesh_setup default_mesh_setup = { |
89 | /* cfg80211_join_mesh() will pick a channel if needed */ |
90 | .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, |
91 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, |
92 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, |
93 | .auth_id = 0, /* open */ |
94 | .ie = NULL, |
95 | .ie_len = 0, |
96 | .is_secure = false, |
97 | .user_mpm = false, |
98 | .beacon_interval = MESH_DEFAULT_BEACON_INTERVAL, |
99 | .dtim_period = MESH_DEFAULT_DTIM_PERIOD, |
100 | }; |
101 | |
102 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, |
103 | struct net_device *dev, |
104 | struct mesh_setup *setup, |
105 | const struct mesh_config *conf) |
106 | { |
107 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
108 | int err; |
109 | |
110 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); |
111 | |
112 | lockdep_assert_wiphy(wdev->wiphy); |
113 | |
114 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
115 | return -EOPNOTSUPP; |
116 | |
117 | if (!(rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && |
118 | setup->is_secure) |
119 | return -EOPNOTSUPP; |
120 | |
121 | if (wdev->u.mesh.id_len) |
122 | return -EALREADY; |
123 | |
124 | if (!setup->mesh_id_len) |
125 | return -EINVAL; |
126 | |
127 | if (!rdev->ops->join_mesh) |
128 | return -EOPNOTSUPP; |
129 | |
130 | if (!setup->chandef.chan) { |
131 | /* if no channel explicitly given, use preset channel */ |
132 | setup->chandef = wdev->u.mesh.preset_chandef; |
133 | } |
134 | |
135 | if (!setup->chandef.chan) { |
136 | /* if we don't have that either, use the first usable channel */ |
137 | enum nl80211_band band; |
138 | |
139 | for (band = 0; band < NUM_NL80211_BANDS; band++) { |
140 | struct ieee80211_supported_band *sband; |
141 | struct ieee80211_channel *chan; |
142 | int i; |
143 | |
144 | sband = rdev->wiphy.bands[band]; |
145 | if (!sband) |
146 | continue; |
147 | |
148 | for (i = 0; i < sband->n_channels; i++) { |
149 | chan = &sband->channels[i]; |
150 | if (chan->flags & (IEEE80211_CHAN_NO_IR | |
151 | IEEE80211_CHAN_DISABLED | |
152 | IEEE80211_CHAN_RADAR)) |
153 | continue; |
154 | setup->chandef.chan = chan; |
155 | break; |
156 | } |
157 | |
158 | if (setup->chandef.chan) |
159 | break; |
160 | } |
161 | |
162 | /* no usable channel ... */ |
163 | if (!setup->chandef.chan) |
164 | return -EINVAL; |
165 | |
166 | setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT; |
167 | setup->chandef.center_freq1 = setup->chandef.chan->center_freq; |
168 | } |
169 | |
170 | /* |
171 | * check if basic rates are available otherwise use mandatory rates as |
172 | * basic rates |
173 | */ |
174 | if (!setup->basic_rates) { |
175 | struct ieee80211_supported_band *sband = |
176 | rdev->wiphy.bands[setup->chandef.chan->band]; |
177 | |
178 | if (setup->chandef.chan->band == NL80211_BAND_2GHZ) { |
179 | int i; |
180 | |
181 | /* |
182 | * Older versions selected the mandatory rates for |
183 | * 2.4 GHz as well, but were broken in that only |
184 | * 1 Mbps was regarded as a mandatory rate. Keep |
185 | * using just 1 Mbps as the default basic rate for |
186 | * mesh to be interoperable with older versions. |
187 | */ |
188 | for (i = 0; i < sband->n_bitrates; i++) { |
189 | if (sband->bitrates[i].bitrate == 10) { |
190 | setup->basic_rates = BIT(i); |
191 | break; |
192 | } |
193 | } |
194 | } else { |
195 | setup->basic_rates = ieee80211_mandatory_rates(sband); |
196 | } |
197 | } |
198 | |
199 | err = cfg80211_chandef_dfs_required(wiphy: &rdev->wiphy, |
200 | chandef: &setup->chandef, |
201 | iftype: NL80211_IFTYPE_MESH_POINT); |
202 | if (err < 0) |
203 | return err; |
204 | if (err > 0 && !setup->userspace_handles_dfs) |
205 | return -EINVAL; |
206 | |
207 | if (!cfg80211_reg_can_beacon(wiphy: &rdev->wiphy, chandef: &setup->chandef, |
208 | iftype: NL80211_IFTYPE_MESH_POINT)) |
209 | return -EINVAL; |
210 | |
211 | err = rdev_join_mesh(rdev, dev, conf, setup); |
212 | if (!err) { |
213 | memcpy(wdev->u.mesh.id, setup->mesh_id, setup->mesh_id_len); |
214 | wdev->u.mesh.id_len = setup->mesh_id_len; |
215 | wdev->u.mesh.chandef = setup->chandef; |
216 | wdev->u.mesh.beacon_interval = setup->beacon_interval; |
217 | } |
218 | |
219 | return err; |
220 | } |
221 | |
222 | int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, |
223 | struct wireless_dev *wdev, |
224 | struct cfg80211_chan_def *chandef) |
225 | { |
226 | int err; |
227 | |
228 | /* |
229 | * Workaround for libertas (only!), it puts the interface |
230 | * into mesh mode but doesn't implement join_mesh. Instead, |
231 | * it is configured via sysfs and then joins the mesh when |
232 | * you set the channel. Note that the libertas mesh isn't |
233 | * compatible with 802.11 mesh. |
234 | */ |
235 | if (rdev->ops->libertas_set_mesh_channel) { |
236 | if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT) |
237 | return -EINVAL; |
238 | |
239 | if (!netif_running(dev: wdev->netdev)) |
240 | return -ENETDOWN; |
241 | |
242 | err = rdev_libertas_set_mesh_channel(rdev, dev: wdev->netdev, |
243 | chan: chandef->chan); |
244 | if (!err) |
245 | wdev->u.mesh.chandef = *chandef; |
246 | |
247 | return err; |
248 | } |
249 | |
250 | if (wdev->u.mesh.id_len) |
251 | return -EBUSY; |
252 | |
253 | wdev->u.mesh.preset_chandef = *chandef; |
254 | return 0; |
255 | } |
256 | |
257 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, |
258 | struct net_device *dev) |
259 | { |
260 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
261 | int err; |
262 | |
263 | lockdep_assert_wiphy(wdev->wiphy); |
264 | |
265 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
266 | return -EOPNOTSUPP; |
267 | |
268 | if (!rdev->ops->leave_mesh) |
269 | return -EOPNOTSUPP; |
270 | |
271 | if (!wdev->u.mesh.id_len) |
272 | return -ENOTCONN; |
273 | |
274 | err = rdev_leave_mesh(rdev, dev); |
275 | if (!err) { |
276 | wdev->conn_owner_nlportid = 0; |
277 | wdev->u.mesh.id_len = 0; |
278 | wdev->u.mesh.beacon_interval = 0; |
279 | memset(&wdev->u.mesh.chandef, 0, |
280 | sizeof(wdev->u.mesh.chandef)); |
281 | rdev_set_qos_map(rdev, dev, NULL); |
282 | cfg80211_sched_dfs_chan_update(rdev); |
283 | } |
284 | |
285 | return err; |
286 | } |
287 | |