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