]>
Commit | Line | Data |
---|---|---|
ea60a6aa DK |
1 | /* cfg80211 support |
2 | * | |
3 | * See copyright notice in main.c | |
4 | */ | |
5 | #include <linux/ieee80211.h> | |
6 | #include <net/cfg80211.h> | |
7 | #include "hw.h" | |
8 | #include "main.h" | |
9 | #include "orinoco.h" | |
10 | ||
11 | #include "cfg.h" | |
12 | ||
13 | /* Supported bitrates. Must agree with hw.c */ | |
14 | static struct ieee80211_rate orinoco_rates[] = { | |
15 | { .bitrate = 10 }, | |
16 | { .bitrate = 20 }, | |
17 | { .bitrate = 55 }, | |
18 | { .bitrate = 110 }, | |
19 | }; | |
20 | ||
21 | static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid; | |
22 | ||
23 | /* Called after orinoco_private is allocated. */ | |
24 | void orinoco_wiphy_init(struct wiphy *wiphy) | |
25 | { | |
26 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
27 | ||
28 | wiphy->privid = orinoco_wiphy_privid; | |
29 | ||
30 | set_wiphy_dev(wiphy, priv->dev); | |
31 | } | |
32 | ||
33 | /* Called after firmware is initialised */ | |
34 | int orinoco_wiphy_register(struct wiphy *wiphy) | |
35 | { | |
36 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
37 | int i, channels = 0; | |
38 | ||
39 | if (priv->firmware_type == FIRMWARE_TYPE_AGERE) | |
40 | wiphy->max_scan_ssids = 1; | |
41 | else | |
42 | wiphy->max_scan_ssids = 0; | |
43 | ||
44 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | |
45 | ||
46 | /* TODO: should we set if we only have demo ad-hoc? | |
47 | * (priv->has_port3) | |
48 | */ | |
49 | if (priv->has_ibss) | |
50 | wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); | |
51 | ||
52 | if (!priv->broken_monitor || force_monitor) | |
53 | wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | |
54 | ||
55 | priv->band.bitrates = orinoco_rates; | |
56 | priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates); | |
57 | ||
58 | /* Only support channels allowed by the card EEPROM */ | |
59 | for (i = 0; i < NUM_CHANNELS; i++) { | |
60 | if (priv->channel_mask & (1 << i)) { | |
61 | priv->channels[i].center_freq = | |
13c1ac57 | 62 | ieee80211_channel_to_frequency(i + 1, |
57fbcce3 | 63 | NL80211_BAND_2GHZ); |
ea60a6aa DK |
64 | channels++; |
65 | } | |
66 | } | |
67 | priv->band.channels = priv->channels; | |
68 | priv->band.n_channels = channels; | |
69 | ||
57fbcce3 | 70 | wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; |
ea60a6aa DK |
71 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
72 | ||
73 | i = 0; | |
74 | if (priv->has_wep) { | |
75 | priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40; | |
76 | i++; | |
77 | ||
78 | if (priv->has_big_wep) { | |
79 | priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104; | |
80 | i++; | |
81 | } | |
82 | } | |
83 | if (priv->has_wpa) { | |
84 | priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP; | |
85 | i++; | |
86 | } | |
87 | wiphy->cipher_suites = priv->cipher_suites; | |
88 | wiphy->n_cipher_suites = i; | |
89 | ||
90 | wiphy->rts_threshold = priv->rts_thresh; | |
91 | if (!priv->has_mwo) | |
c3d41503 DK |
92 | wiphy->frag_threshold = priv->frag_thresh + 1; |
93 | wiphy->retry_short = priv->short_retry_limit; | |
94 | wiphy->retry_long = priv->long_retry_limit; | |
ea60a6aa DK |
95 | |
96 | return wiphy_register(wiphy); | |
97 | } | |
98 | ||
5217c571 DK |
99 | static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, |
100 | enum nl80211_iftype type, u32 *flags, | |
101 | struct vif_params *params) | |
102 | { | |
103 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
104 | int err = 0; | |
105 | unsigned long lock; | |
106 | ||
107 | if (orinoco_lock(priv, &lock) != 0) | |
108 | return -EBUSY; | |
109 | ||
110 | switch (type) { | |
111 | case NL80211_IFTYPE_ADHOC: | |
112 | if (!priv->has_ibss && !priv->has_port3) | |
113 | err = -EINVAL; | |
114 | break; | |
115 | ||
116 | case NL80211_IFTYPE_STATION: | |
117 | break; | |
118 | ||
119 | case NL80211_IFTYPE_MONITOR: | |
120 | if (priv->broken_monitor && !force_monitor) { | |
c96c31e4 JP |
121 | wiphy_warn(wiphy, |
122 | "Monitor mode support is buggy in this firmware, not enabling\n"); | |
5217c571 DK |
123 | err = -EINVAL; |
124 | } | |
125 | break; | |
126 | ||
127 | default: | |
128 | err = -EINVAL; | |
129 | } | |
ea60a6aa | 130 | |
5217c571 DK |
131 | if (!err) { |
132 | priv->iw_mode = type; | |
133 | set_port_type(priv); | |
134 | err = orinoco_commit(priv); | |
135 | } | |
136 | ||
137 | orinoco_unlock(priv, &lock); | |
138 | ||
139 | return err; | |
140 | } | |
141 | ||
fd014284 | 142 | static int orinoco_scan(struct wiphy *wiphy, |
c63cdbe8 DK |
143 | struct cfg80211_scan_request *request) |
144 | { | |
145 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
146 | int err; | |
147 | ||
148 | if (!request) | |
149 | return -EINVAL; | |
150 | ||
151 | if (priv->scan_request && priv->scan_request != request) | |
152 | return -EBUSY; | |
153 | ||
154 | priv->scan_request = request; | |
155 | ||
156 | err = orinoco_hw_trigger_scan(priv, request->ssids); | |
a3ad38e8 | 157 | /* On error the we aren't processing the request */ |
158 | if (err) | |
159 | priv->scan_request = NULL; | |
c63cdbe8 DK |
160 | |
161 | return err; | |
162 | } | |
163 | ||
e8c9bd5b | 164 | static int orinoco_set_monitor_channel(struct wiphy *wiphy, |
683b6d3b | 165 | struct cfg80211_chan_def *chandef) |
7e2ce646 HS |
166 | { |
167 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
168 | int err = 0; | |
169 | unsigned long flags; | |
170 | int channel; | |
171 | ||
683b6d3b | 172 | if (!chandef->chan) |
7e2ce646 HS |
173 | return -EINVAL; |
174 | ||
683b6d3b | 175 | if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) |
7e2ce646 HS |
176 | return -EINVAL; |
177 | ||
57fbcce3 | 178 | if (chandef->chan->band != NL80211_BAND_2GHZ) |
7e2ce646 HS |
179 | return -EINVAL; |
180 | ||
13c1ac57 | 181 | channel = ieee80211_frequency_to_channel(chandef->chan->center_freq); |
7e2ce646 HS |
182 | |
183 | if ((channel < 1) || (channel > NUM_CHANNELS) || | |
933d5943 | 184 | !(priv->channel_mask & (1 << (channel - 1)))) |
7e2ce646 HS |
185 | return -EINVAL; |
186 | ||
187 | if (orinoco_lock(priv, &flags) != 0) | |
188 | return -EBUSY; | |
189 | ||
190 | priv->channel = channel; | |
191 | if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { | |
192 | /* Fast channel change - no commit if successful */ | |
933d5943 | 193 | struct hermes *hw = &priv->hw; |
b42f2074 | 194 | err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | |
7e2ce646 HS |
195 | HERMES_TEST_SET_CHANNEL, |
196 | channel, NULL); | |
197 | } | |
198 | orinoco_unlock(priv, &flags); | |
199 | ||
200 | return err; | |
201 | } | |
202 | ||
c3d41503 DK |
203 | static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed) |
204 | { | |
205 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
206 | int frag_value = -1; | |
207 | int rts_value = -1; | |
208 | int err = 0; | |
209 | ||
210 | if (changed & WIPHY_PARAM_RETRY_SHORT) { | |
211 | /* Setting short retry not supported */ | |
212 | err = -EINVAL; | |
213 | } | |
214 | ||
215 | if (changed & WIPHY_PARAM_RETRY_LONG) { | |
216 | /* Setting long retry not supported */ | |
217 | err = -EINVAL; | |
218 | } | |
219 | ||
220 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { | |
221 | /* Set fragmentation */ | |
222 | if (priv->has_mwo) { | |
e79dd09b | 223 | if (wiphy->frag_threshold == -1) |
c3d41503 DK |
224 | frag_value = 0; |
225 | else { | |
226 | printk(KERN_WARNING "%s: Fixed fragmentation " | |
227 | "is not supported on this firmware. " | |
228 | "Using MWO robust instead.\n", | |
229 | priv->ndev->name); | |
230 | frag_value = 1; | |
231 | } | |
232 | } else { | |
e79dd09b | 233 | if (wiphy->frag_threshold == -1) |
c3d41503 DK |
234 | frag_value = 2346; |
235 | else if ((wiphy->frag_threshold < 257) || | |
236 | (wiphy->frag_threshold > 2347)) | |
237 | err = -EINVAL; | |
238 | else | |
239 | /* cfg80211 value is 257-2347 (odd only) | |
240 | * orinoco rid has range 256-2346 (even only) */ | |
241 | frag_value = wiphy->frag_threshold & ~0x1; | |
242 | } | |
243 | } | |
244 | ||
245 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | |
246 | /* Set RTS. | |
247 | * | |
248 | * Prism documentation suggests default of 2432, | |
249 | * and a range of 0-3000. | |
250 | * | |
251 | * Current implementation uses 2347 as the default and | |
252 | * the upper limit. | |
253 | */ | |
254 | ||
e79dd09b | 255 | if (wiphy->rts_threshold == -1) |
c3d41503 DK |
256 | rts_value = 2347; |
257 | else if (wiphy->rts_threshold > 2347) | |
258 | err = -EINVAL; | |
259 | else | |
260 | rts_value = wiphy->rts_threshold; | |
261 | } | |
262 | ||
263 | if (!err) { | |
264 | unsigned long flags; | |
265 | ||
266 | if (orinoco_lock(priv, &flags) != 0) | |
267 | return -EBUSY; | |
268 | ||
269 | if (frag_value >= 0) { | |
270 | if (priv->has_mwo) | |
271 | priv->mwo_robust = frag_value; | |
272 | else | |
273 | priv->frag_thresh = frag_value; | |
274 | } | |
275 | if (rts_value >= 0) | |
276 | priv->rts_thresh = rts_value; | |
277 | ||
278 | err = orinoco_commit(priv); | |
279 | ||
280 | orinoco_unlock(priv, &flags); | |
281 | } | |
282 | ||
283 | return err; | |
284 | } | |
285 | ||
5217c571 DK |
286 | const struct cfg80211_ops orinoco_cfg_ops = { |
287 | .change_virtual_intf = orinoco_change_vif, | |
e8c9bd5b | 288 | .set_monitor_channel = orinoco_set_monitor_channel, |
c63cdbe8 | 289 | .scan = orinoco_scan, |
c3d41503 | 290 | .set_wiphy_params = orinoco_set_wiphy_params, |
ea60a6aa | 291 | }; |