]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/wireless/mesh.c
Merge branch 'master' of git://1984.lsi.us.es/nf-next
[karo-tx-linux.git] / net / wireless / mesh.c
1 #include <linux/ieee80211.h>
2 #include <linux/export.h>
3 #include <net/cfg80211.h>
4 #include "nl80211.h"
5 #include "core.h"
6 #include "rdev-ops.h"
7
8 /* Default values, timeouts in ms */
9 #define MESH_TTL                31
10 #define MESH_DEFAULT_ELEMENT_TTL 31
11 #define MESH_MAX_RETR           3
12 #define MESH_RET_T              100
13 #define MESH_CONF_T             100
14 #define MESH_HOLD_T             100
15
16 #define MESH_PATH_TIMEOUT       5000
17 #define MESH_RANN_INTERVAL      5000
18 #define MESH_PATH_TO_ROOT_TIMEOUT      6000
19 #define MESH_ROOT_INTERVAL     5000
20 #define MESH_ROOT_CONFIRMATION_INTERVAL 2000
21
22 /*
23  * Minimum interval between two consecutive PREQs originated by the same
24  * interface
25  */
26 #define MESH_PREQ_MIN_INT       10
27 #define MESH_PERR_MIN_INT       100
28 #define MESH_DIAM_TRAVERSAL_TIME 50
29
30 #define MESH_RSSI_THRESHOLD     0
31
32 /*
33  * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds
34  * before timing out.  This way it will remain ACTIVE and no data frames
35  * will be unnecessarily held in the pending queue.
36  */
37 #define MESH_PATH_REFRESH_TIME                  1000
38 #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
39
40 /* Default maximum number of established plinks per interface */
41 #define MESH_MAX_ESTAB_PLINKS   32
42
43 #define MESH_MAX_PREQ_RETRIES   4
44
45 #define MESH_SYNC_NEIGHBOR_OFFSET_MAX 50
46
47 const struct mesh_config default_mesh_config = {
48         .dot11MeshRetryTimeout = MESH_RET_T,
49         .dot11MeshConfirmTimeout = MESH_CONF_T,
50         .dot11MeshHoldingTimeout = MESH_HOLD_T,
51         .dot11MeshMaxRetries = MESH_MAX_RETR,
52         .dot11MeshTTL = MESH_TTL,
53         .element_ttl = MESH_DEFAULT_ELEMENT_TTL,
54         .auto_open_plinks = true,
55         .dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS,
56         .dot11MeshNbrOffsetMaxNeighbor = MESH_SYNC_NEIGHBOR_OFFSET_MAX,
57         .dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT,
58         .dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT,
59         .dot11MeshHWMPperrMinInterval = MESH_PERR_MIN_INT,
60         .dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME,
61         .dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES,
62         .path_refresh_time = MESH_PATH_REFRESH_TIME,
63         .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
64         .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
65         .dot11MeshGateAnnouncementProtocol = false,
66         .dot11MeshForwarding = true,
67         .rssi_threshold = MESH_RSSI_THRESHOLD,
68         .ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED,
69         .dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT,
70         .dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL,
71         .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL,
72 };
73
74 const struct mesh_setup default_mesh_setup = {
75         /* cfg80211_join_mesh() will pick a channel if needed */
76         .channel = NULL,
77         .channel_type = NL80211_CHAN_NO_HT,
78         .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
79         .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
80         .path_metric = IEEE80211_PATH_METRIC_AIRTIME,
81         .ie = NULL,
82         .ie_len = 0,
83         .is_secure = false,
84 };
85
86 int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
87                          struct net_device *dev,
88                          struct mesh_setup *setup,
89                          const struct mesh_config *conf)
90 {
91         struct wireless_dev *wdev = dev->ieee80211_ptr;
92         int err;
93
94         BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
95
96         ASSERT_WDEV_LOCK(wdev);
97
98         if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
99                 return -EOPNOTSUPP;
100
101         if (!(rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
102               setup->is_secure)
103                 return -EOPNOTSUPP;
104
105         if (wdev->mesh_id_len)
106                 return -EALREADY;
107
108         if (!setup->mesh_id_len)
109                 return -EINVAL;
110
111         if (!rdev->ops->join_mesh)
112                 return -EOPNOTSUPP;
113
114         if (!setup->channel) {
115                 /* if no channel explicitly given, use preset channel */
116                 setup->channel = wdev->preset_chan;
117                 setup->channel_type = wdev->preset_chantype;
118         }
119
120         if (!setup->channel) {
121                 /* if we don't have that either, use the first usable channel */
122                 enum ieee80211_band band;
123
124                 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
125                         struct ieee80211_supported_band *sband;
126                         struct ieee80211_channel *chan;
127                         int i;
128
129                         sband = rdev->wiphy.bands[band];
130                         if (!sband)
131                                 continue;
132
133                         for (i = 0; i < sband->n_channels; i++) {
134                                 chan = &sband->channels[i];
135                                 if (chan->flags & (IEEE80211_CHAN_NO_IBSS |
136                                                    IEEE80211_CHAN_PASSIVE_SCAN |
137                                                    IEEE80211_CHAN_DISABLED |
138                                                    IEEE80211_CHAN_RADAR))
139                                         continue;
140                                 setup->channel = chan;
141                                 break;
142                         }
143
144                         if (setup->channel)
145                                 break;
146                 }
147
148                 /* no usable channel ... */
149                 if (!setup->channel)
150                         return -EINVAL;
151
152                 setup->channel_type = NL80211_CHAN_NO_HT;
153         }
154
155         if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel,
156                                           setup->channel_type))
157                 return -EINVAL;
158
159         err = cfg80211_can_use_chan(rdev, wdev, setup->channel,
160                                     CHAN_MODE_SHARED);
161         if (err)
162                 return err;
163
164         err = rdev_join_mesh(rdev, dev, conf, setup);
165         if (!err) {
166                 memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
167                 wdev->mesh_id_len = setup->mesh_id_len;
168                 wdev->channel = setup->channel;
169         }
170
171         return err;
172 }
173
174 int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
175                        struct net_device *dev,
176                        struct mesh_setup *setup,
177                        const struct mesh_config *conf)
178 {
179         struct wireless_dev *wdev = dev->ieee80211_ptr;
180         int err;
181
182         mutex_lock(&rdev->devlist_mtx);
183         wdev_lock(wdev);
184         err = __cfg80211_join_mesh(rdev, dev, setup, conf);
185         wdev_unlock(wdev);
186         mutex_unlock(&rdev->devlist_mtx);
187
188         return err;
189 }
190
191 int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
192                            struct wireless_dev *wdev, int freq,
193                            enum nl80211_channel_type channel_type)
194 {
195         struct ieee80211_channel *channel;
196         int err;
197
198         channel = rdev_freq_to_chan(rdev, freq, channel_type);
199         if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
200                                                       channel,
201                                                       channel_type)) {
202                 return -EINVAL;
203         }
204
205         /*
206          * Workaround for libertas (only!), it puts the interface
207          * into mesh mode but doesn't implement join_mesh. Instead,
208          * it is configured via sysfs and then joins the mesh when
209          * you set the channel. Note that the libertas mesh isn't
210          * compatible with 802.11 mesh.
211          */
212         if (rdev->ops->libertas_set_mesh_channel) {
213                 if (channel_type != NL80211_CHAN_NO_HT)
214                         return -EINVAL;
215
216                 if (!netif_running(wdev->netdev))
217                         return -ENETDOWN;
218
219                 err = cfg80211_can_use_chan(rdev, wdev, channel,
220                                             CHAN_MODE_SHARED);
221                 if (err)
222                         return err;
223
224                 err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
225                                                      channel);
226                 if (!err)
227                         wdev->channel = channel;
228
229                 return err;
230         }
231
232         if (wdev->mesh_id_len)
233                 return -EBUSY;
234
235         wdev->preset_chan = channel;
236         wdev->preset_chantype = channel_type;
237         return 0;
238 }
239
240 void cfg80211_notify_new_peer_candidate(struct net_device *dev,
241                 const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
242 {
243         struct wireless_dev *wdev = dev->ieee80211_ptr;
244
245         trace_cfg80211_notify_new_peer_candidate(dev, macaddr);
246         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
247                 return;
248
249         nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev,
250                         macaddr, ie, ie_len, gfp);
251 }
252 EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
253
254 static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
255                                  struct net_device *dev)
256 {
257         struct wireless_dev *wdev = dev->ieee80211_ptr;
258         int err;
259
260         ASSERT_WDEV_LOCK(wdev);
261
262         if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
263                 return -EOPNOTSUPP;
264
265         if (!rdev->ops->leave_mesh)
266                 return -EOPNOTSUPP;
267
268         if (!wdev->mesh_id_len)
269                 return -ENOTCONN;
270
271         err = rdev_leave_mesh(rdev, dev);
272         if (!err) {
273                 wdev->mesh_id_len = 0;
274                 wdev->channel = NULL;
275         }
276
277         return err;
278 }
279
280 int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
281                         struct net_device *dev)
282 {
283         struct wireless_dev *wdev = dev->ieee80211_ptr;
284         int err;
285
286         wdev_lock(wdev);
287         err = __cfg80211_leave_mesh(rdev, dev);
288         wdev_unlock(wdev);
289
290         return err;
291 }