Root/
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 | #define MESH_DEFAULT_PLINK_TIMEOUT 1800 /* timeout in seconds */ |
22 | |
23 | /* |
24 | * Minimum interval between two consecutive PREQs originated by the same |
25 | * interface |
26 | */ |
27 | #define MESH_PREQ_MIN_INT 10 |
28 | #define MESH_PERR_MIN_INT 100 |
29 | #define MESH_DIAM_TRAVERSAL_TIME 50 |
30 | |
31 | #define MESH_RSSI_THRESHOLD 0 |
32 | |
33 | /* |
34 | * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds |
35 | * before timing out. This way it will remain ACTIVE and no data frames |
36 | * will be unnecessarily held in the pending queue. |
37 | */ |
38 | #define MESH_PATH_REFRESH_TIME 1000 |
39 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) |
40 | |
41 | /* Default maximum number of established plinks per interface */ |
42 | #define MESH_MAX_ESTAB_PLINKS 32 |
43 | |
44 | #define MESH_MAX_PREQ_RETRIES 4 |
45 | |
46 | #define MESH_SYNC_NEIGHBOR_OFFSET_MAX 50 |
47 | |
48 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units (=TUs) */ |
49 | #define MESH_DEFAULT_DTIM_PERIOD 2 |
50 | #define MESH_DEFAULT_AWAKE_WINDOW 10 /* in 1024 us units (=TUs) */ |
51 | |
52 | const struct mesh_config default_mesh_config = { |
53 | .dot11MeshRetryTimeout = MESH_RET_T, |
54 | .dot11MeshConfirmTimeout = MESH_CONF_T, |
55 | .dot11MeshHoldingTimeout = MESH_HOLD_T, |
56 | .dot11MeshMaxRetries = MESH_MAX_RETR, |
57 | .dot11MeshTTL = MESH_TTL, |
58 | .element_ttl = MESH_DEFAULT_ELEMENT_TTL, |
59 | .auto_open_plinks = true, |
60 | .dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS, |
61 | .dot11MeshNbrOffsetMaxNeighbor = MESH_SYNC_NEIGHBOR_OFFSET_MAX, |
62 | .dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT, |
63 | .dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT, |
64 | .dot11MeshHWMPperrMinInterval = MESH_PERR_MIN_INT, |
65 | .dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME, |
66 | .dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES, |
67 | .path_refresh_time = MESH_PATH_REFRESH_TIME, |
68 | .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT, |
69 | .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL, |
70 | .dot11MeshGateAnnouncementProtocol = false, |
71 | .dot11MeshForwarding = true, |
72 | .rssi_threshold = MESH_RSSI_THRESHOLD, |
73 | .ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED, |
74 | .dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT, |
75 | .dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL, |
76 | .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL, |
77 | .power_mode = NL80211_MESH_POWER_ACTIVE, |
78 | .dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW, |
79 | .plink_timeout = MESH_DEFAULT_PLINK_TIMEOUT, |
80 | }; |
81 | |
82 | const struct mesh_setup default_mesh_setup = { |
83 | /* cfg80211_join_mesh() will pick a channel if needed */ |
84 | .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, |
85 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, |
86 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, |
87 | .auth_id = 0, /* open */ |
88 | .ie = NULL, |
89 | .ie_len = 0, |
90 | .is_secure = false, |
91 | .user_mpm = false, |
92 | .beacon_interval = MESH_DEFAULT_BEACON_INTERVAL, |
93 | .dtim_period = MESH_DEFAULT_DTIM_PERIOD, |
94 | }; |
95 | |
96 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, |
97 | struct net_device *dev, |
98 | struct mesh_setup *setup, |
99 | const struct mesh_config *conf) |
100 | { |
101 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
102 | int err; |
103 | |
104 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); |
105 | |
106 | ASSERT_WDEV_LOCK(wdev); |
107 | |
108 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
109 | return -EOPNOTSUPP; |
110 | |
111 | if (!(rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && |
112 | setup->is_secure) |
113 | return -EOPNOTSUPP; |
114 | |
115 | if (wdev->mesh_id_len) |
116 | return -EALREADY; |
117 | |
118 | if (!setup->mesh_id_len) |
119 | return -EINVAL; |
120 | |
121 | if (!rdev->ops->join_mesh) |
122 | return -EOPNOTSUPP; |
123 | |
124 | if (!setup->chandef.chan) { |
125 | /* if no channel explicitly given, use preset channel */ |
126 | setup->chandef = wdev->preset_chandef; |
127 | } |
128 | |
129 | if (!setup->chandef.chan) { |
130 | /* if we don't have that either, use the first usable channel */ |
131 | enum ieee80211_band band; |
132 | |
133 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
134 | struct ieee80211_supported_band *sband; |
135 | struct ieee80211_channel *chan; |
136 | int i; |
137 | |
138 | sband = rdev->wiphy.bands[band]; |
139 | if (!sband) |
140 | continue; |
141 | |
142 | for (i = 0; i < sband->n_channels; i++) { |
143 | chan = &sband->channels[i]; |
144 | if (chan->flags & (IEEE80211_CHAN_NO_IBSS | |
145 | IEEE80211_CHAN_PASSIVE_SCAN | |
146 | IEEE80211_CHAN_DISABLED | |
147 | IEEE80211_CHAN_RADAR)) |
148 | continue; |
149 | setup->chandef.chan = chan; |
150 | break; |
151 | } |
152 | |
153 | if (setup->chandef.chan) |
154 | break; |
155 | } |
156 | |
157 | /* no usable channel ... */ |
158 | if (!setup->chandef.chan) |
159 | return -EINVAL; |
160 | |
161 | setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT; |
162 | setup->chandef.center_freq1 = setup->chandef.chan->center_freq; |
163 | } |
164 | |
165 | /* |
166 | * check if basic rates are available otherwise use mandatory rates as |
167 | * basic rates |
168 | */ |
169 | if (!setup->basic_rates) { |
170 | enum nl80211_bss_scan_width scan_width; |
171 | struct ieee80211_supported_band *sband = |
172 | rdev->wiphy.bands[setup->chandef.chan->band]; |
173 | scan_width = cfg80211_chandef_to_scan_width(&setup->chandef); |
174 | setup->basic_rates = ieee80211_mandatory_rates(sband, |
175 | scan_width); |
176 | } |
177 | |
178 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) |
179 | return -EINVAL; |
180 | |
181 | err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan, |
182 | CHAN_MODE_SHARED); |
183 | if (err) |
184 | return err; |
185 | |
186 | err = rdev_join_mesh(rdev, dev, conf, setup); |
187 | if (!err) { |
188 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
189 | wdev->mesh_id_len = setup->mesh_id_len; |
190 | wdev->channel = setup->chandef.chan; |
191 | } |
192 | |
193 | return err; |
194 | } |
195 | |
196 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, |
197 | struct net_device *dev, |
198 | struct mesh_setup *setup, |
199 | const struct mesh_config *conf) |
200 | { |
201 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
202 | int err; |
203 | |
204 | wdev_lock(wdev); |
205 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); |
206 | wdev_unlock(wdev); |
207 | |
208 | return err; |
209 | } |
210 | |
211 | int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, |
212 | struct wireless_dev *wdev, |
213 | struct cfg80211_chan_def *chandef) |
214 | { |
215 | int err; |
216 | |
217 | /* |
218 | * Workaround for libertas (only!), it puts the interface |
219 | * into mesh mode but doesn't implement join_mesh. Instead, |
220 | * it is configured via sysfs and then joins the mesh when |
221 | * you set the channel. Note that the libertas mesh isn't |
222 | * compatible with 802.11 mesh. |
223 | */ |
224 | if (rdev->ops->libertas_set_mesh_channel) { |
225 | if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT) |
226 | return -EINVAL; |
227 | |
228 | if (!netif_running(wdev->netdev)) |
229 | return -ENETDOWN; |
230 | |
231 | err = cfg80211_can_use_chan(rdev, wdev, chandef->chan, |
232 | CHAN_MODE_SHARED); |
233 | if (err) |
234 | return err; |
235 | |
236 | err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, |
237 | chandef->chan); |
238 | if (!err) |
239 | wdev->channel = chandef->chan; |
240 | |
241 | return err; |
242 | } |
243 | |
244 | if (wdev->mesh_id_len) |
245 | return -EBUSY; |
246 | |
247 | wdev->preset_chandef = *chandef; |
248 | return 0; |
249 | } |
250 | |
251 | static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, |
252 | struct net_device *dev) |
253 | { |
254 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
255 | int err; |
256 | |
257 | ASSERT_WDEV_LOCK(wdev); |
258 | |
259 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
260 | return -EOPNOTSUPP; |
261 | |
262 | if (!rdev->ops->leave_mesh) |
263 | return -EOPNOTSUPP; |
264 | |
265 | if (!wdev->mesh_id_len) |
266 | return -ENOTCONN; |
267 | |
268 | err = rdev_leave_mesh(rdev, dev); |
269 | if (!err) { |
270 | wdev->mesh_id_len = 0; |
271 | wdev->channel = NULL; |
272 | } |
273 | |
274 | return err; |
275 | } |
276 | |
277 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, |
278 | struct net_device *dev) |
279 | { |
280 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
281 | int err; |
282 | |
283 | wdev_lock(wdev); |
284 | err = __cfg80211_leave_mesh(rdev, dev); |
285 | wdev_unlock(wdev); |
286 | |
287 | return err; |
288 | } |
289 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9