]> Pileus Git - ~andy/linux/blob - drivers/net/wireless/iwmc3200wifi/cfg80211.c
cfg80211: pass netdev to change_virtual_intf
[~andy/linux] / drivers / net / wireless / iwmc3200wifi / cfg80211.c
1 /*
2  * Intel Wireless Multicomm 3200 WiFi driver
3  *
4  * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5  * Samuel Ortiz <samuel.ortiz@intel.com>
6  * Zhu Yi <yi.zhu@intel.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version
10  * 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  *
22  */
23
24 #include <linux/kernel.h>
25 #include <linux/netdevice.h>
26 #include <linux/wireless.h>
27 #include <linux/ieee80211.h>
28 #include <net/cfg80211.h>
29
30 #include "iwm.h"
31 #include "commands.h"
32 #include "cfg80211.h"
33 #include "debug.h"
34
35 #define RATETAB_ENT(_rate, _rateid, _flags) \
36         {                                                               \
37                 .bitrate        = (_rate),                              \
38                 .hw_value       = (_rateid),                            \
39                 .flags          = (_flags),                             \
40         }
41
42 #define CHAN2G(_channel, _freq, _flags) {                       \
43         .band                   = IEEE80211_BAND_2GHZ,          \
44         .center_freq            = (_freq),                      \
45         .hw_value               = (_channel),                   \
46         .flags                  = (_flags),                     \
47         .max_antenna_gain       = 0,                            \
48         .max_power              = 30,                           \
49 }
50
51 #define CHAN5G(_channel, _flags) {                              \
52         .band                   = IEEE80211_BAND_5GHZ,          \
53         .center_freq            = 5000 + (5 * (_channel)),      \
54         .hw_value               = (_channel),                   \
55         .flags                  = (_flags),                     \
56         .max_antenna_gain       = 0,                            \
57         .max_power              = 30,                           \
58 }
59
60 static struct ieee80211_rate iwm_rates[] = {
61         RATETAB_ENT(10,  0x1,   0),
62         RATETAB_ENT(20,  0x2,   0),
63         RATETAB_ENT(55,  0x4,   0),
64         RATETAB_ENT(110, 0x8,   0),
65         RATETAB_ENT(60,  0x10,  0),
66         RATETAB_ENT(90,  0x20,  0),
67         RATETAB_ENT(120, 0x40,  0),
68         RATETAB_ENT(180, 0x80,  0),
69         RATETAB_ENT(240, 0x100, 0),
70         RATETAB_ENT(360, 0x200, 0),
71         RATETAB_ENT(480, 0x400, 0),
72         RATETAB_ENT(540, 0x800, 0),
73 };
74
75 #define iwm_a_rates             (iwm_rates + 4)
76 #define iwm_a_rates_size        8
77 #define iwm_g_rates             (iwm_rates + 0)
78 #define iwm_g_rates_size        12
79
80 static struct ieee80211_channel iwm_2ghz_channels[] = {
81         CHAN2G(1, 2412, 0),
82         CHAN2G(2, 2417, 0),
83         CHAN2G(3, 2422, 0),
84         CHAN2G(4, 2427, 0),
85         CHAN2G(5, 2432, 0),
86         CHAN2G(6, 2437, 0),
87         CHAN2G(7, 2442, 0),
88         CHAN2G(8, 2447, 0),
89         CHAN2G(9, 2452, 0),
90         CHAN2G(10, 2457, 0),
91         CHAN2G(11, 2462, 0),
92         CHAN2G(12, 2467, 0),
93         CHAN2G(13, 2472, 0),
94         CHAN2G(14, 2484, 0),
95 };
96
97 static struct ieee80211_channel iwm_5ghz_a_channels[] = {
98         CHAN5G(34, 0),          CHAN5G(36, 0),
99         CHAN5G(38, 0),          CHAN5G(40, 0),
100         CHAN5G(42, 0),          CHAN5G(44, 0),
101         CHAN5G(46, 0),          CHAN5G(48, 0),
102         CHAN5G(52, 0),          CHAN5G(56, 0),
103         CHAN5G(60, 0),          CHAN5G(64, 0),
104         CHAN5G(100, 0),         CHAN5G(104, 0),
105         CHAN5G(108, 0),         CHAN5G(112, 0),
106         CHAN5G(116, 0),         CHAN5G(120, 0),
107         CHAN5G(124, 0),         CHAN5G(128, 0),
108         CHAN5G(132, 0),         CHAN5G(136, 0),
109         CHAN5G(140, 0),         CHAN5G(149, 0),
110         CHAN5G(153, 0),         CHAN5G(157, 0),
111         CHAN5G(161, 0),         CHAN5G(165, 0),
112         CHAN5G(184, 0),         CHAN5G(188, 0),
113         CHAN5G(192, 0),         CHAN5G(196, 0),
114         CHAN5G(200, 0),         CHAN5G(204, 0),
115         CHAN5G(208, 0),         CHAN5G(212, 0),
116         CHAN5G(216, 0),
117 };
118
119 static struct ieee80211_supported_band iwm_band_2ghz = {
120         .channels = iwm_2ghz_channels,
121         .n_channels = ARRAY_SIZE(iwm_2ghz_channels),
122         .bitrates = iwm_g_rates,
123         .n_bitrates = iwm_g_rates_size,
124 };
125
126 static struct ieee80211_supported_band iwm_band_5ghz = {
127         .channels = iwm_5ghz_a_channels,
128         .n_channels = ARRAY_SIZE(iwm_5ghz_a_channels),
129         .bitrates = iwm_a_rates,
130         .n_bitrates = iwm_a_rates_size,
131 };
132
133 int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
134 {
135         struct wiphy *wiphy = iwm_to_wiphy(iwm);
136         struct iwm_bss_info *bss, *next;
137         struct iwm_umac_notif_bss_info *umac_bss;
138         struct ieee80211_mgmt *mgmt;
139         struct ieee80211_channel *channel;
140         struct ieee80211_supported_band *band;
141         s32 signal;
142         int freq;
143
144         list_for_each_entry_safe(bss, next, &iwm->bss_list, node) {
145                 umac_bss = bss->bss;
146                 mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
147
148                 if (umac_bss->band == UMAC_BAND_2GHZ)
149                         band = wiphy->bands[IEEE80211_BAND_2GHZ];
150                 else if (umac_bss->band == UMAC_BAND_5GHZ)
151                         band = wiphy->bands[IEEE80211_BAND_5GHZ];
152                 else {
153                         IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band);
154                         return -EINVAL;
155                 }
156
157                 freq = ieee80211_channel_to_frequency(umac_bss->channel);
158                 channel = ieee80211_get_channel(wiphy, freq);
159                 signal = umac_bss->rssi * 100;
160
161                 if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
162                                                le16_to_cpu(umac_bss->frame_len),
163                                                signal, GFP_KERNEL))
164                         return -EINVAL;
165         }
166
167         return 0;
168 }
169
170 static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
171                                      struct net_device *ndev,
172                                      enum nl80211_iftype type, u32 *flags,
173                                      struct vif_params *params)
174 {
175         struct wireless_dev *wdev;
176         struct iwm_priv *iwm;
177         u32 old_mode;
178
179         wdev = ndev->ieee80211_ptr;
180         iwm = ndev_to_iwm(ndev);
181         old_mode = iwm->conf.mode;
182
183         switch (type) {
184         case NL80211_IFTYPE_STATION:
185                 iwm->conf.mode = UMAC_MODE_BSS;
186                 break;
187         case NL80211_IFTYPE_ADHOC:
188                 iwm->conf.mode = UMAC_MODE_IBSS;
189                 break;
190         default:
191                 return -EOPNOTSUPP;
192         }
193
194         wdev->iftype = type;
195
196         if ((old_mode == iwm->conf.mode) || !iwm->umac_profile)
197                 return 0;
198
199         iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
200
201         if (iwm->umac_profile_active) {
202                 int ret = iwm_invalidate_mlme_profile(iwm);
203                 if (ret < 0)
204                         IWM_ERR(iwm, "Couldn't invalidate profile\n");
205         }
206
207         return 0;
208 }
209
210 static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
211                              struct cfg80211_scan_request *request)
212 {
213         struct iwm_priv *iwm = ndev_to_iwm(ndev);
214         int ret;
215
216         if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
217                 IWM_ERR(iwm, "Scan while device is not ready\n");
218                 return -EIO;
219         }
220
221         if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) {
222                 IWM_ERR(iwm, "Scanning already\n");
223                 return -EAGAIN;
224         }
225
226         if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) {
227                 IWM_ERR(iwm, "Scanning being aborted\n");
228                 return -EAGAIN;
229         }
230
231         set_bit(IWM_STATUS_SCANNING, &iwm->status);
232
233         ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids);
234         if (ret) {
235                 clear_bit(IWM_STATUS_SCANNING, &iwm->status);
236                 return ret;
237         }
238
239         iwm->scan_request = request;
240         return 0;
241 }
242
243 static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
244 {
245         struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
246
247         if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
248             (iwm->conf.rts_threshold != wiphy->rts_threshold)) {
249                 int ret;
250
251                 iwm->conf.rts_threshold = wiphy->rts_threshold;
252
253                 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
254                                              CFG_RTS_THRESHOLD,
255                                              iwm->conf.rts_threshold);
256                 if (ret < 0)
257                         return ret;
258         }
259
260         if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
261             (iwm->conf.frag_threshold != wiphy->frag_threshold)) {
262                 int ret;
263
264                 iwm->conf.frag_threshold = wiphy->frag_threshold;
265
266                 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
267                                              CFG_FRAG_THRESHOLD,
268                                              iwm->conf.frag_threshold);
269                 if (ret < 0)
270                         return ret;
271         }
272
273         return 0;
274 }
275
276 static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
277                                   struct cfg80211_ibss_params *params)
278 {
279         struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
280         struct ieee80211_channel *chan = params->channel;
281         struct cfg80211_bss *bss;
282
283         if (!test_bit(IWM_STATUS_READY, &iwm->status))
284                 return -EIO;
285
286         /* UMAC doesn't support creating IBSS network with specified bssid.
287          * This should be removed after we have join only mode supported. */
288         if (params->bssid)
289                 return -EOPNOTSUPP;
290
291         bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
292                                 params->ssid, params->ssid_len);
293         if (!bss) {
294                 iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len);
295                 schedule_timeout_interruptible(2 * HZ);
296                 bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
297                                         params->ssid, params->ssid_len);
298         }
299         /* IBSS join only mode is not supported by UMAC ATM */
300         if (bss) {
301                 cfg80211_put_bss(bss);
302                 return -EOPNOTSUPP;
303         }
304
305         iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
306         iwm->umac_profile->ibss.band = chan->band;
307         iwm->umac_profile->ibss.channel = iwm->channel;
308         iwm->umac_profile->ssid.ssid_len = params->ssid_len;
309         memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
310
311         if (params->bssid)
312                 memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
313
314         return iwm_send_mlme_profile(iwm);
315 }
316
317 static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
318 {
319         struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
320
321         if (iwm->umac_profile_active)
322                 return iwm_invalidate_mlme_profile(iwm);
323
324         return 0;
325 }
326
327 static struct cfg80211_ops iwm_cfg80211_ops = {
328         .change_virtual_intf = iwm_cfg80211_change_iface,
329         .scan = iwm_cfg80211_scan,
330         .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
331         .join_ibss = iwm_cfg80211_join_ibss,
332         .leave_ibss = iwm_cfg80211_leave_ibss,
333 };
334
335 struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
336 {
337         int ret = 0;
338         struct wireless_dev *wdev;
339
340         /*
341          * We're trying to have the following memory
342          * layout:
343          *
344          * +-------------------------+
345          * | struct wiphy            |
346          * +-------------------------+
347          * | struct iwm_priv         |
348          * +-------------------------+
349          * | bus private data        |
350          * | (e.g. iwm_priv_sdio)    |
351          * +-------------------------+
352          *
353          */
354
355         wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
356         if (!wdev) {
357                 dev_err(dev, "Couldn't allocate wireless device\n");
358                 return ERR_PTR(-ENOMEM);
359         }
360
361         wdev->wiphy = wiphy_new(&iwm_cfg80211_ops,
362                                 sizeof(struct iwm_priv) + sizeof_bus);
363         if (!wdev->wiphy) {
364                 dev_err(dev, "Couldn't allocate wiphy device\n");
365                 ret = -ENOMEM;
366                 goto out_err_new;
367         }
368
369         set_wiphy_dev(wdev->wiphy, dev);
370         wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
371         wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
372                                        BIT(NL80211_IFTYPE_ADHOC);
373         wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz;
374         wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
375         wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
376
377         ret = wiphy_register(wdev->wiphy);
378         if (ret < 0) {
379                 dev_err(dev, "Couldn't register wiphy device\n");
380                 goto out_err_register;
381         }
382
383         return wdev;
384
385  out_err_register:
386         wiphy_free(wdev->wiphy);
387
388  out_err_new:
389         kfree(wdev);
390
391         return ERR_PTR(ret);
392 }
393
394 void iwm_wdev_free(struct iwm_priv *iwm)
395 {
396         struct wireless_dev *wdev = iwm_to_wdev(iwm);
397
398         if (!wdev)
399                 return;
400
401         wiphy_unregister(wdev->wiphy);
402         wiphy_free(wdev->wiphy);
403         kfree(wdev);
404 }