blob: 0aa389564c712e12b24e9142dc7e3af2299358fd [file] [log] [blame]
Zhu Yibb9f8692009-05-21 21:20:45 +08001/*
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>
Samuel Ortiz13e0fe702009-06-15 21:59:52 +020026#include <linux/etherdevice.h>
Zhu Yibb9f8692009-05-21 21:20:45 +080027#include <linux/wireless.h>
28#include <linux/ieee80211.h>
29#include <net/cfg80211.h>
30
31#include "iwm.h"
32#include "commands.h"
33#include "cfg80211.h"
34#include "debug.h"
35
36#define RATETAB_ENT(_rate, _rateid, _flags) \
37 { \
38 .bitrate = (_rate), \
39 .hw_value = (_rateid), \
40 .flags = (_flags), \
41 }
42
43#define CHAN2G(_channel, _freq, _flags) { \
44 .band = IEEE80211_BAND_2GHZ, \
45 .center_freq = (_freq), \
46 .hw_value = (_channel), \
47 .flags = (_flags), \
48 .max_antenna_gain = 0, \
49 .max_power = 30, \
50}
51
52#define CHAN5G(_channel, _flags) { \
53 .band = IEEE80211_BAND_5GHZ, \
54 .center_freq = 5000 + (5 * (_channel)), \
55 .hw_value = (_channel), \
56 .flags = (_flags), \
57 .max_antenna_gain = 0, \
58 .max_power = 30, \
59}
60
61static struct ieee80211_rate iwm_rates[] = {
62 RATETAB_ENT(10, 0x1, 0),
63 RATETAB_ENT(20, 0x2, 0),
64 RATETAB_ENT(55, 0x4, 0),
65 RATETAB_ENT(110, 0x8, 0),
66 RATETAB_ENT(60, 0x10, 0),
67 RATETAB_ENT(90, 0x20, 0),
68 RATETAB_ENT(120, 0x40, 0),
69 RATETAB_ENT(180, 0x80, 0),
70 RATETAB_ENT(240, 0x100, 0),
71 RATETAB_ENT(360, 0x200, 0),
72 RATETAB_ENT(480, 0x400, 0),
73 RATETAB_ENT(540, 0x800, 0),
74};
75
76#define iwm_a_rates (iwm_rates + 4)
77#define iwm_a_rates_size 8
78#define iwm_g_rates (iwm_rates + 0)
79#define iwm_g_rates_size 12
80
81static struct ieee80211_channel iwm_2ghz_channels[] = {
82 CHAN2G(1, 2412, 0),
83 CHAN2G(2, 2417, 0),
84 CHAN2G(3, 2422, 0),
85 CHAN2G(4, 2427, 0),
86 CHAN2G(5, 2432, 0),
87 CHAN2G(6, 2437, 0),
88 CHAN2G(7, 2442, 0),
89 CHAN2G(8, 2447, 0),
90 CHAN2G(9, 2452, 0),
91 CHAN2G(10, 2457, 0),
92 CHAN2G(11, 2462, 0),
93 CHAN2G(12, 2467, 0),
94 CHAN2G(13, 2472, 0),
95 CHAN2G(14, 2484, 0),
96};
97
98static struct ieee80211_channel iwm_5ghz_a_channels[] = {
99 CHAN5G(34, 0), CHAN5G(36, 0),
100 CHAN5G(38, 0), CHAN5G(40, 0),
101 CHAN5G(42, 0), CHAN5G(44, 0),
102 CHAN5G(46, 0), CHAN5G(48, 0),
103 CHAN5G(52, 0), CHAN5G(56, 0),
104 CHAN5G(60, 0), CHAN5G(64, 0),
105 CHAN5G(100, 0), CHAN5G(104, 0),
106 CHAN5G(108, 0), CHAN5G(112, 0),
107 CHAN5G(116, 0), CHAN5G(120, 0),
108 CHAN5G(124, 0), CHAN5G(128, 0),
109 CHAN5G(132, 0), CHAN5G(136, 0),
110 CHAN5G(140, 0), CHAN5G(149, 0),
111 CHAN5G(153, 0), CHAN5G(157, 0),
112 CHAN5G(161, 0), CHAN5G(165, 0),
113 CHAN5G(184, 0), CHAN5G(188, 0),
114 CHAN5G(192, 0), CHAN5G(196, 0),
115 CHAN5G(200, 0), CHAN5G(204, 0),
116 CHAN5G(208, 0), CHAN5G(212, 0),
117 CHAN5G(216, 0),
118};
119
120static struct ieee80211_supported_band iwm_band_2ghz = {
121 .channels = iwm_2ghz_channels,
122 .n_channels = ARRAY_SIZE(iwm_2ghz_channels),
123 .bitrates = iwm_g_rates,
124 .n_bitrates = iwm_g_rates_size,
125};
126
127static struct ieee80211_supported_band iwm_band_5ghz = {
128 .channels = iwm_5ghz_a_channels,
129 .n_channels = ARRAY_SIZE(iwm_5ghz_a_channels),
130 .bitrates = iwm_a_rates,
131 .n_bitrates = iwm_a_rates_size,
132};
133
Samuel Ortiz13e0fe702009-06-15 21:59:52 +0200134static int iwm_key_init(struct iwm_key *key, u8 key_index,
135 const u8 *mac_addr, struct key_params *params)
136{
137 key->hdr.key_idx = key_index;
138 if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
139 key->hdr.multicast = 1;
140 memset(key->hdr.mac, 0xff, ETH_ALEN);
141 } else {
142 key->hdr.multicast = 0;
143 memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
144 }
145
146 if (params) {
147 if (params->key_len > WLAN_MAX_KEY_LEN ||
148 params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
149 return -EINVAL;
150
151 key->cipher = params->cipher;
152 key->key_len = params->key_len;
153 key->seq_len = params->seq_len;
154 memcpy(key->key, params->key, key->key_len);
155 memcpy(key->seq, params->seq, key->seq_len);
156 }
157
158 return 0;
159}
160
161static int iwm_reset_profile(struct iwm_priv *iwm)
162{
163 int ret;
164
165 if (!iwm->umac_profile_active)
166 return 0;
167
168 /*
169 * If there is a current active profile, but no
170 * default key, it's not worth trying to associate again.
171 */
172 if (iwm->default_key < 0)
173 return 0;
174
175 /*
176 * Here we have an active profile, but a key setting changed.
177 * We thus have to invalidate the current profile, and push the
178 * new one. Keys will be pushed when association takes place.
179 */
180 ret = iwm_invalidate_mlme_profile(iwm);
181 if (ret < 0) {
182 IWM_ERR(iwm, "Couldn't invalidate profile\n");
183 return ret;
184 }
185
186 return iwm_send_mlme_profile(iwm);
187}
188
189static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
190 u8 key_index, const u8 *mac_addr,
191 struct key_params *params)
192{
193 struct iwm_priv *iwm = ndev_to_iwm(ndev);
194 struct iwm_key *key = &iwm->keys[key_index];
195 int ret;
196
197 IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
198
199 memset(key, 0, sizeof(struct iwm_key));
200 ret = iwm_key_init(key, key_index, mac_addr, params);
201 if (ret < 0) {
202 IWM_ERR(iwm, "Invalid key_params\n");
203 return ret;
204 }
205
206 /*
207 * The WEP keys can be set before or after setting the essid.
208 * We need to handle both cases by simply pushing the keys after
209 * we send the profile.
210 * If the profile is not set yet (i.e. we're pushing keys before
211 * the essid), we set the cipher appropriately.
212 * If the profile is set, we havent associated yet because our
213 * cipher was incorrectly set. So we invalidate and send the
214 * profile again.
215 */
216 if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
217 key->cipher == WLAN_CIPHER_SUITE_WEP104) {
218 u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher;
219 u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher;
220
221 IWM_DBG_WEXT(iwm, DBG, "WEP key\n");
222
223 if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
224 *ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
225 if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
226 *ucast_cipher = *mcast_cipher =
227 UMAC_CIPHER_TYPE_WEP_104;
228
229 return iwm_reset_profile(iwm);
230 }
231
232 return iwm_set_key(iwm, 0, key);
233}
234
235static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
236 u8 key_index, const u8 *mac_addr, void *cookie,
237 void (*callback)(void *cookie,
238 struct key_params*))
239{
240 struct iwm_priv *iwm = ndev_to_iwm(ndev);
241 struct iwm_key *key = &iwm->keys[key_index];
242 struct key_params params;
243
244 IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
245
246 memset(&params, 0, sizeof(params));
247
248 params.cipher = key->cipher;
249 params.key_len = key->key_len;
250 params.seq_len = key->seq_len;
251 params.seq = key->seq;
252 params.key = key->key;
253
254 callback(cookie, &params);
255
256 return key->key_len ? 0 : -ENOENT;
257}
258
259
260static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
261 u8 key_index, const u8 *mac_addr)
262{
263 struct iwm_priv *iwm = ndev_to_iwm(ndev);
264 struct iwm_key *key = &iwm->keys[key_index];
265
266 if (!iwm->keys[key_index].key_len) {
267 IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
268 return 0;
269 }
270
271 if (key_index == iwm->default_key)
272 iwm->default_key = -1;
273
Samuel Ortiz35497162009-06-15 21:59:54 +0200274 /* If the interface is down, we just cache this */
275 if (!test_bit(IWM_STATUS_READY, &iwm->status))
276 return 0;
277
Samuel Ortiz13e0fe702009-06-15 21:59:52 +0200278 return iwm_set_key(iwm, 1, key);
279}
280
281static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
282 struct net_device *ndev,
283 u8 key_index)
284{
285 struct iwm_priv *iwm = ndev_to_iwm(ndev);
286 int ret;
287
288 IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
289
290 if (!iwm->keys[key_index].key_len) {
291 IWM_ERR(iwm, "Key %d not used\n", key_index);
292 return -EINVAL;
293 }
294
Samuel Ortiz35497162009-06-15 21:59:54 +0200295 iwm->default_key = key_index;
296
297 /* If the interface is down, we just cache this */
298 if (!test_bit(IWM_STATUS_READY, &iwm->status))
299 return 0;
300
Samuel Ortiz13e0fe702009-06-15 21:59:52 +0200301 ret = iwm_set_tx_key(iwm, key_index);
302 if (ret < 0)
303 return ret;
304
Samuel Ortiz13e0fe702009-06-15 21:59:52 +0200305 return iwm_reset_profile(iwm);
306}
307
308
Zhu Yibb9f8692009-05-21 21:20:45 +0800309int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
310{
311 struct wiphy *wiphy = iwm_to_wiphy(iwm);
312 struct iwm_bss_info *bss, *next;
313 struct iwm_umac_notif_bss_info *umac_bss;
314 struct ieee80211_mgmt *mgmt;
315 struct ieee80211_channel *channel;
316 struct ieee80211_supported_band *band;
317 s32 signal;
318 int freq;
319
320 list_for_each_entry_safe(bss, next, &iwm->bss_list, node) {
321 umac_bss = bss->bss;
322 mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
323
324 if (umac_bss->band == UMAC_BAND_2GHZ)
325 band = wiphy->bands[IEEE80211_BAND_2GHZ];
326 else if (umac_bss->band == UMAC_BAND_5GHZ)
327 band = wiphy->bands[IEEE80211_BAND_5GHZ];
328 else {
329 IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band);
330 return -EINVAL;
331 }
332
333 freq = ieee80211_channel_to_frequency(umac_bss->channel);
334 channel = ieee80211_get_channel(wiphy, freq);
335 signal = umac_bss->rssi * 100;
336
337 if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
338 le16_to_cpu(umac_bss->frame_len),
339 signal, GFP_KERNEL))
340 return -EINVAL;
341 }
342
343 return 0;
344}
345
Johannes Berge36d56b2009-06-09 21:04:43 +0200346static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
347 struct net_device *ndev,
Zhu Yibb9f8692009-05-21 21:20:45 +0800348 enum nl80211_iftype type, u32 *flags,
349 struct vif_params *params)
350{
Zhu Yibb9f8692009-05-21 21:20:45 +0800351 struct wireless_dev *wdev;
352 struct iwm_priv *iwm;
353 u32 old_mode;
354
Zhu Yibb9f8692009-05-21 21:20:45 +0800355 wdev = ndev->ieee80211_ptr;
356 iwm = ndev_to_iwm(ndev);
357 old_mode = iwm->conf.mode;
358
359 switch (type) {
360 case NL80211_IFTYPE_STATION:
361 iwm->conf.mode = UMAC_MODE_BSS;
362 break;
363 case NL80211_IFTYPE_ADHOC:
364 iwm->conf.mode = UMAC_MODE_IBSS;
365 break;
366 default:
367 return -EOPNOTSUPP;
368 }
369
370 wdev->iftype = type;
371
372 if ((old_mode == iwm->conf.mode) || !iwm->umac_profile)
373 return 0;
374
375 iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
376
377 if (iwm->umac_profile_active) {
378 int ret = iwm_invalidate_mlme_profile(iwm);
379 if (ret < 0)
380 IWM_ERR(iwm, "Couldn't invalidate profile\n");
381 }
382
383 return 0;
384}
385
386static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
387 struct cfg80211_scan_request *request)
388{
389 struct iwm_priv *iwm = ndev_to_iwm(ndev);
390 int ret;
391
392 if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
393 IWM_ERR(iwm, "Scan while device is not ready\n");
394 return -EIO;
395 }
396
397 if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) {
398 IWM_ERR(iwm, "Scanning already\n");
399 return -EAGAIN;
400 }
401
402 if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) {
403 IWM_ERR(iwm, "Scanning being aborted\n");
404 return -EAGAIN;
405 }
406
407 set_bit(IWM_STATUS_SCANNING, &iwm->status);
408
409 ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids);
410 if (ret) {
411 clear_bit(IWM_STATUS_SCANNING, &iwm->status);
412 return ret;
413 }
414
415 iwm->scan_request = request;
416 return 0;
417}
418
419static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
420{
421 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
422
423 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
424 (iwm->conf.rts_threshold != wiphy->rts_threshold)) {
425 int ret;
426
427 iwm->conf.rts_threshold = wiphy->rts_threshold;
428
429 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
430 CFG_RTS_THRESHOLD,
431 iwm->conf.rts_threshold);
432 if (ret < 0)
433 return ret;
434 }
435
436 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
437 (iwm->conf.frag_threshold != wiphy->frag_threshold)) {
438 int ret;
439
440 iwm->conf.frag_threshold = wiphy->frag_threshold;
441
Samuel Ortizb63b0ea2009-05-26 11:10:46 +0800442 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
Zhu Yibb9f8692009-05-21 21:20:45 +0800443 CFG_FRAG_THRESHOLD,
444 iwm->conf.frag_threshold);
445 if (ret < 0)
446 return ret;
447 }
448
449 return 0;
450}
451
452static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
453 struct cfg80211_ibss_params *params)
454{
455 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
456 struct ieee80211_channel *chan = params->channel;
457 struct cfg80211_bss *bss;
458
459 if (!test_bit(IWM_STATUS_READY, &iwm->status))
460 return -EIO;
461
462 /* UMAC doesn't support creating IBSS network with specified bssid.
463 * This should be removed after we have join only mode supported. */
464 if (params->bssid)
465 return -EOPNOTSUPP;
466
467 bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
468 params->ssid, params->ssid_len);
469 if (!bss) {
470 iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len);
471 schedule_timeout_interruptible(2 * HZ);
472 bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
473 params->ssid, params->ssid_len);
474 }
475 /* IBSS join only mode is not supported by UMAC ATM */
476 if (bss) {
477 cfg80211_put_bss(bss);
478 return -EOPNOTSUPP;
479 }
480
481 iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
482 iwm->umac_profile->ibss.band = chan->band;
483 iwm->umac_profile->ibss.channel = iwm->channel;
484 iwm->umac_profile->ssid.ssid_len = params->ssid_len;
485 memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
486
487 if (params->bssid)
488 memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
489
490 return iwm_send_mlme_profile(iwm);
491}
492
493static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
494{
495 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
496
497 if (iwm->umac_profile_active)
498 return iwm_invalidate_mlme_profile(iwm);
499
500 return 0;
501}
502
Zhu Yi257862f2009-06-15 21:59:56 +0200503static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
504 enum tx_power_setting type, int dbm)
505{
506 switch (type) {
507 case TX_POWER_AUTOMATIC:
508 return 0;
509 default:
510 return -EOPNOTSUPP;
511 }
512
513 return 0;
514}
515
516static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
517{
518 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
519
520 *dbm = iwm->txpower;
521
522 return 0;
523}
524
Johannes Bergbc92afd2009-07-01 21:26:57 +0200525static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
526 struct net_device *dev,
527 bool enabled, int timeout)
528{
529 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
530 u32 power_index;
531
532 if (enabled)
533 power_index = IWM_POWER_INDEX_DEFAULT;
534 else
535 power_index = IWM_POWER_INDEX_MIN;
536
537 if (power_index == iwm->conf.power_index)
538 return 0;
539
540 iwm->conf.power_index = power_index;
541
542 return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
543 CFG_POWER_INDEX, iwm->conf.power_index);
544}
545
Zhu Yibb9f8692009-05-21 21:20:45 +0800546static struct cfg80211_ops iwm_cfg80211_ops = {
547 .change_virtual_intf = iwm_cfg80211_change_iface,
Samuel Ortiz13e0fe702009-06-15 21:59:52 +0200548 .add_key = iwm_cfg80211_add_key,
549 .get_key = iwm_cfg80211_get_key,
550 .del_key = iwm_cfg80211_del_key,
551 .set_default_key = iwm_cfg80211_set_default_key,
Zhu Yibb9f8692009-05-21 21:20:45 +0800552 .scan = iwm_cfg80211_scan,
553 .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
554 .join_ibss = iwm_cfg80211_join_ibss,
555 .leave_ibss = iwm_cfg80211_leave_ibss,
Zhu Yi257862f2009-06-15 21:59:56 +0200556 .set_tx_power = iwm_cfg80211_set_txpower,
557 .get_tx_power = iwm_cfg80211_get_txpower,
Johannes Bergbc92afd2009-07-01 21:26:57 +0200558 .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
Zhu Yibb9f8692009-05-21 21:20:45 +0800559};
560
Zhu Yi49b77722009-07-16 17:34:08 +0800561static const u32 cipher_suites[] = {
562 WLAN_CIPHER_SUITE_WEP40,
563 WLAN_CIPHER_SUITE_WEP104,
564 WLAN_CIPHER_SUITE_TKIP,
565 WLAN_CIPHER_SUITE_CCMP,
566};
567
Zhu Yibb9f8692009-05-21 21:20:45 +0800568struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
569{
570 int ret = 0;
571 struct wireless_dev *wdev;
572
573 /*
574 * We're trying to have the following memory
575 * layout:
576 *
577 * +-------------------------+
578 * | struct wiphy |
579 * +-------------------------+
580 * | struct iwm_priv |
581 * +-------------------------+
582 * | bus private data |
583 * | (e.g. iwm_priv_sdio) |
584 * +-------------------------+
585 *
586 */
587
588 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
589 if (!wdev) {
590 dev_err(dev, "Couldn't allocate wireless device\n");
591 return ERR_PTR(-ENOMEM);
592 }
593
594 wdev->wiphy = wiphy_new(&iwm_cfg80211_ops,
595 sizeof(struct iwm_priv) + sizeof_bus);
596 if (!wdev->wiphy) {
597 dev_err(dev, "Couldn't allocate wiphy device\n");
598 ret = -ENOMEM;
599 goto out_err_new;
600 }
601
602 set_wiphy_dev(wdev->wiphy, dev);
603 wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
604 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
605 BIT(NL80211_IFTYPE_ADHOC);
606 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz;
607 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
608 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
609
Zhu Yi49b77722009-07-16 17:34:08 +0800610 wdev->wiphy->cipher_suites = cipher_suites;
611 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
612
Zhu Yibb9f8692009-05-21 21:20:45 +0800613 ret = wiphy_register(wdev->wiphy);
614 if (ret < 0) {
615 dev_err(dev, "Couldn't register wiphy device\n");
616 goto out_err_register;
617 }
618
619 return wdev;
620
621 out_err_register:
622 wiphy_free(wdev->wiphy);
623
624 out_err_new:
625 kfree(wdev);
626
627 return ERR_PTR(ret);
628}
629
630void iwm_wdev_free(struct iwm_priv *iwm)
631{
632 struct wireless_dev *wdev = iwm_to_wdev(iwm);
633
634 if (!wdev)
635 return;
636
637 wiphy_unregister(wdev->wiphy);
638 wiphy_free(wdev->wiphy);
639 kfree(wdev);
640}