1bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi/*
2bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Intel Wireless Multicomm 3200 WiFi driver
3bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi *
4bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Samuel Ortiz <samuel.ortiz@intel.com>
6bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Zhu Yi <yi.zhu@intel.com>
7bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi *
8bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * This program is free software; you can redistribute it and/or
9bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * modify it under the terms of the GNU General Public License version
10bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 2 as published by the Free Software Foundation.
11bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi *
12bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * This program is distributed in the hope that it will be useful,
13bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * but WITHOUT ANY WARRANTY; without even the implied warranty of
14bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * GNU General Public License for more details.
16bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi *
17bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * You should have received a copy of the GNU General Public License
18bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * along with this program; if not, write to the Free Software
19bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 02110-1301, USA.
21bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi *
22bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi */
23bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
24bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/kernel.h>
25bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/netdevice.h>
26d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h>
2713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz#include <linux/etherdevice.h>
28bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/wireless.h>
29bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/ieee80211.h>
305a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
31bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <net/cfg80211.h>
32bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
33bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "iwm.h"
34bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "commands.h"
35bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "cfg80211.h"
36bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "debug.h"
37bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
38bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#define RATETAB_ENT(_rate, _rateid, _flags) \
39bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	{								\
40bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		.bitrate	= (_rate),				\
41bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		.hw_value	= (_rateid),				\
42bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		.flags		= (_flags),				\
43bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
44bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
45bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#define CHAN2G(_channel, _freq, _flags) {			\
46bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.band			= IEEE80211_BAND_2GHZ,		\
47bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.center_freq		= (_freq),			\
48bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.hw_value		= (_channel),			\
49bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.flags			= (_flags),			\
50bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.max_antenna_gain	= 0,				\
51bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.max_power		= 30,				\
52bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}
53bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
54bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#define CHAN5G(_channel, _flags) {				\
55bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.band			= IEEE80211_BAND_5GHZ,		\
56bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.center_freq		= 5000 + (5 * (_channel)),	\
57bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.hw_value		= (_channel),			\
58bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.flags			= (_flags),			\
59bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.max_antenna_gain	= 0,				\
60bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.max_power		= 30,				\
61bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}
62bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
63bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic struct ieee80211_rate iwm_rates[] = {
64bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(10,  0x1,   0),
65bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(20,  0x2,   0),
66bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(55,  0x4,   0),
67bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(110, 0x8,   0),
68bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(60,  0x10,  0),
69bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(90,  0x20,  0),
70bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(120, 0x40,  0),
71bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(180, 0x80,  0),
72bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(240, 0x100, 0),
73bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(360, 0x200, 0),
74bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(480, 0x400, 0),
75bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	RATETAB_ENT(540, 0x800, 0),
76bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi};
77bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
78bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#define iwm_a_rates		(iwm_rates + 4)
79bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#define iwm_a_rates_size	8
80bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#define iwm_g_rates		(iwm_rates + 0)
81bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#define iwm_g_rates_size	12
82bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
83bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic struct ieee80211_channel iwm_2ghz_channels[] = {
84bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(1, 2412, 0),
85bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(2, 2417, 0),
86bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(3, 2422, 0),
87bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(4, 2427, 0),
88bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(5, 2432, 0),
89bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(6, 2437, 0),
90bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(7, 2442, 0),
91bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(8, 2447, 0),
92bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(9, 2452, 0),
93bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(10, 2457, 0),
94bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(11, 2462, 0),
95bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(12, 2467, 0),
96bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(13, 2472, 0),
97bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN2G(14, 2484, 0),
98bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi};
99bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
100bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic struct ieee80211_channel iwm_5ghz_a_channels[] = {
101bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(34, 0),		CHAN5G(36, 0),
102bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(38, 0),		CHAN5G(40, 0),
103bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(42, 0),		CHAN5G(44, 0),
104bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(46, 0),		CHAN5G(48, 0),
105bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(52, 0),		CHAN5G(56, 0),
106bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(60, 0),		CHAN5G(64, 0),
107bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(100, 0),		CHAN5G(104, 0),
108bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(108, 0),		CHAN5G(112, 0),
109bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(116, 0),		CHAN5G(120, 0),
110bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(124, 0),		CHAN5G(128, 0),
111bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(132, 0),		CHAN5G(136, 0),
112bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(140, 0),		CHAN5G(149, 0),
113bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(153, 0),		CHAN5G(157, 0),
114bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(161, 0),		CHAN5G(165, 0),
115bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(184, 0),		CHAN5G(188, 0),
116bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(192, 0),		CHAN5G(196, 0),
117bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(200, 0),		CHAN5G(204, 0),
118bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(208, 0),		CHAN5G(212, 0),
119bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	CHAN5G(216, 0),
120bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi};
121bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
122bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic struct ieee80211_supported_band iwm_band_2ghz = {
123bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.channels = iwm_2ghz_channels,
124bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.n_channels = ARRAY_SIZE(iwm_2ghz_channels),
125bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.bitrates = iwm_g_rates,
126bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.n_bitrates = iwm_g_rates_size,
127bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi};
128bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
129bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic struct ieee80211_supported_band iwm_band_5ghz = {
130bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.channels = iwm_5ghz_a_channels,
131bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.n_channels = ARRAY_SIZE(iwm_5ghz_a_channels),
132bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.bitrates = iwm_a_rates,
133bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.n_bitrates = iwm_a_rates_size,
134bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi};
135bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
13613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortizstatic int iwm_key_init(struct iwm_key *key, u8 key_index,
13713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz			const u8 *mac_addr, struct key_params *params)
13813e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz{
13913e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	key->hdr.key_idx = key_index;
14013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
14113e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		key->hdr.multicast = 1;
14213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		memset(key->hdr.mac, 0xff, ETH_ALEN);
14313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	} else {
14413e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		key->hdr.multicast = 0;
14513e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
14613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	}
14713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
14813e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	if (params) {
14913e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		if (params->key_len > WLAN_MAX_KEY_LEN ||
15013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		    params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
15113e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz			return -EINVAL;
15213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
15313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		key->cipher = params->cipher;
15413e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		key->key_len = params->key_len;
15513e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		key->seq_len = params->seq_len;
15613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		memcpy(key->key, params->key, key->key_len);
15713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		memcpy(key->seq, params->seq, key->seq_len);
15813e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	}
15913e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
16013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	return 0;
16113e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz}
16213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
16313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortizstatic int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
164e31b82136d1adc7a599b6e99d3321e5831841f5aJohannes Berg				u8 key_index, bool pairwise, const u8 *mac_addr,
16513e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz				struct key_params *params)
16613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz{
16713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	struct iwm_priv *iwm = ndev_to_iwm(ndev);
1685a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter	struct iwm_key *key;
16913e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	int ret;
17013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
17113e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
17213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
1735a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter	if (key_index >= IWM_NUM_KEYS)
1745a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter		return -ENOENT;
1755a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter
1765a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter	key = &iwm->keys[key_index];
17713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	memset(key, 0, sizeof(struct iwm_key));
17813e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	ret = iwm_key_init(key, key_index, mac_addr, params);
17913e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	if (ret < 0) {
18013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		IWM_ERR(iwm, "Invalid key_params\n");
18113e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		return ret;
18213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	}
18313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
18413e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	return iwm_set_key(iwm, 0, key);
18513e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz}
18613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
18713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortizstatic int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
188e31b82136d1adc7a599b6e99d3321e5831841f5aJohannes Berg				u8 key_index, bool pairwise, const u8 *mac_addr,
189e31b82136d1adc7a599b6e99d3321e5831841f5aJohannes Berg				void *cookie,
19013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz				void (*callback)(void *cookie,
19113e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz						 struct key_params*))
19213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz{
19313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	struct iwm_priv *iwm = ndev_to_iwm(ndev);
194f9a703e173849425079e29e63bf960c2625e0a85Dan Carpenter	struct iwm_key *key;
19513e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	struct key_params params;
19613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
19713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
19813e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
199f9a703e173849425079e29e63bf960c2625e0a85Dan Carpenter	if (key_index >= IWM_NUM_KEYS)
200f9a703e173849425079e29e63bf960c2625e0a85Dan Carpenter		return -ENOENT;
201f9a703e173849425079e29e63bf960c2625e0a85Dan Carpenter
20213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	memset(&params, 0, sizeof(params));
20313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
204f9a703e173849425079e29e63bf960c2625e0a85Dan Carpenter	key = &iwm->keys[key_index];
20513e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	params.cipher = key->cipher;
20613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	params.key_len = key->key_len;
20713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	params.seq_len = key->seq_len;
20813e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	params.seq = key->seq;
20913e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	params.key = key->key;
21013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
21113e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	callback(cookie, &params);
21213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
21313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	return key->key_len ? 0 : -ENOENT;
21413e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz}
21513e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
21613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
21713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortizstatic int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
218e31b82136d1adc7a599b6e99d3321e5831841f5aJohannes Berg				u8 key_index, bool pairwise, const u8 *mac_addr)
21913e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz{
22013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	struct iwm_priv *iwm = ndev_to_iwm(ndev);
2215a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter	struct iwm_key *key;
22213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
2235a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter	if (key_index >= IWM_NUM_KEYS)
2245a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter		return -ENOENT;
2255a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter
2265a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter	key = &iwm->keys[key_index];
22713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	if (!iwm->keys[key_index].key_len) {
22813e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
22913e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		return 0;
23013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	}
23113e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
23213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	if (key_index == iwm->default_key)
23313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		iwm->default_key = -1;
23413e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
23513e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	return iwm_set_key(iwm, 1, key);
23613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz}
23713e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
23813e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortizstatic int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
23913e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz					struct net_device *ndev,
240dbd2fd656f2060abfd3a16257f8b51ec60f6d2edJohannes Berg					u8 key_index, bool unicast,
241dbd2fd656f2060abfd3a16257f8b51ec60f6d2edJohannes Berg					bool multicast)
24213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz{
24313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	struct iwm_priv *iwm = ndev_to_iwm(ndev);
24413e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
24513e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
24613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
2475a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter	if (key_index >= IWM_NUM_KEYS)
2485a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter		return -ENOENT;
2495a5ee76e09b1f5a3a550127aecc2ea4d59f17963Dan Carpenter
25013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	if (!iwm->keys[key_index].key_len) {
25113e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		IWM_ERR(iwm, "Key %d not used\n", key_index);
25213e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz		return -EINVAL;
25313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	}
25413e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
2553549716484a95fd16f7fcf8b68699bd4c803b382Samuel Ortiz	iwm->default_key = key_index;
2563549716484a95fd16f7fcf8b68699bd4c803b382Samuel Ortiz
2576e5db0a8454b44bf88fa74cf437a507ec08f436dZhu Yi	return iwm_set_tx_key(iwm, key_index);
25813e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz}
25913e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
260d041811d931d4f515fd58e222757cbc7d6375db4Samuel Ortizstatic int iwm_cfg80211_get_station(struct wiphy *wiphy,
261d041811d931d4f515fd58e222757cbc7d6375db4Samuel Ortiz				    struct net_device *ndev,
262d041811d931d4f515fd58e222757cbc7d6375db4Samuel Ortiz				    u8 *mac, struct station_info *sinfo)
2639967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz{
2649967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	struct iwm_priv *iwm = ndev_to_iwm(ndev);
2659967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
2669967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (memcmp(mac, iwm->bssid, ETH_ALEN))
2679967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return -ENOENT;
2689967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
2699967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	sinfo->filled |= STATION_INFO_TX_BITRATE;
2709967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	sinfo->txrate.legacy = iwm->rate * 10;
2719967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
2729967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
2739967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		sinfo->filled |= STATION_INFO_SIGNAL;
2749967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		sinfo->signal = iwm->wstats.qual.level;
2759967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	}
2769967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
2779967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	return 0;
2789967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz}
2799967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
28013e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz
281bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yiint iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
282bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{
283bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct wiphy *wiphy = iwm_to_wiphy(iwm);
28404d1c22761f33ac8f345665e7ef809c875142425Zhu Yi	struct iwm_bss_info *bss;
285bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct iwm_umac_notif_bss_info *umac_bss;
286bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct ieee80211_mgmt *mgmt;
287bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct ieee80211_channel *channel;
288bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct ieee80211_supported_band *band;
289bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	s32 signal;
290bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	int freq;
291bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
29204d1c22761f33ac8f345665e7ef809c875142425Zhu Yi	list_for_each_entry(bss, &iwm->bss_list, node) {
293bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		umac_bss = bss->bss;
294bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
295bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
296bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		if (umac_bss->band == UMAC_BAND_2GHZ)
297bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi			band = wiphy->bands[IEEE80211_BAND_2GHZ];
298bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		else if (umac_bss->band == UMAC_BAND_5GHZ)
299bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi			band = wiphy->bands[IEEE80211_BAND_5GHZ];
300bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		else {
301bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi			IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band);
302bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi			return -EINVAL;
303bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		}
304bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
30559eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf		freq = ieee80211_channel_to_frequency(umac_bss->channel,
30659eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf						      band->band);
307bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		channel = ieee80211_get_channel(wiphy, freq);
308bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		signal = umac_bss->rssi * 100;
309bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
310bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
311bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi					       le16_to_cpu(umac_bss->frame_len),
312bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi					       signal, GFP_KERNEL))
313bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi			return -EINVAL;
314bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
315bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
316bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	return 0;
317bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}
318bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
319e36d56b64808aec54b68b4e9976180c1da0933b2Johannes Bergstatic int iwm_cfg80211_change_iface(struct wiphy *wiphy,
320e36d56b64808aec54b68b4e9976180c1da0933b2Johannes Berg				     struct net_device *ndev,
321bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi				     enum nl80211_iftype type, u32 *flags,
322bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi				     struct vif_params *params)
323bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{
324bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct wireless_dev *wdev;
325bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct iwm_priv *iwm;
326bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	u32 old_mode;
327bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
328bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wdev = ndev->ieee80211_ptr;
329bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	iwm = ndev_to_iwm(ndev);
330bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	old_mode = iwm->conf.mode;
331bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
332bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	switch (type) {
333bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	case NL80211_IFTYPE_STATION:
334bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		iwm->conf.mode = UMAC_MODE_BSS;
335bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		break;
336bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	case NL80211_IFTYPE_ADHOC:
337bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		iwm->conf.mode = UMAC_MODE_IBSS;
338bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		break;
339bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	default:
340bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return -EOPNOTSUPP;
341bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
342bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
343bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wdev->iftype = type;
344bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
345bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if ((old_mode == iwm->conf.mode) || !iwm->umac_profile)
346bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return 0;
347bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
348bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
349bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
350ae73abf2350de7cbfc5c46a936f4d2a532b36679Zhu Yi	if (iwm->umac_profile_active)
351ae73abf2350de7cbfc5c46a936f4d2a532b36679Zhu Yi		iwm_invalidate_mlme_profile(iwm);
352bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
353bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	return 0;
354bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}
355bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
356bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
357bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi			     struct cfg80211_scan_request *request)
358bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{
359bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct iwm_priv *iwm = ndev_to_iwm(ndev);
360bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	int ret;
361bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
362bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
363bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		IWM_ERR(iwm, "Scan while device is not ready\n");
364bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return -EIO;
365bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
366bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
367bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) {
368bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		IWM_ERR(iwm, "Scanning already\n");
369bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return -EAGAIN;
370bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
371bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
372bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) {
373bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		IWM_ERR(iwm, "Scanning being aborted\n");
374bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return -EAGAIN;
375bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
376bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
377bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	set_bit(IWM_STATUS_SCANNING, &iwm->status);
378bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
379bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids);
380bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (ret) {
381bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		clear_bit(IWM_STATUS_SCANNING, &iwm->status);
382bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return ret;
383bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
384bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
385bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	iwm->scan_request = request;
386bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	return 0;
387bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}
388bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
389bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
390bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{
391bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
392bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
393bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
394bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	    (iwm->conf.rts_threshold != wiphy->rts_threshold)) {
395bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		int ret;
396bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
397bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		iwm->conf.rts_threshold = wiphy->rts_threshold;
398bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
399bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
400bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi					     CFG_RTS_THRESHOLD,
401bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi					     iwm->conf.rts_threshold);
402bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		if (ret < 0)
403bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi			return ret;
404bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
405bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
406bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
407bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	    (iwm->conf.frag_threshold != wiphy->frag_threshold)) {
408bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		int ret;
409bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
410bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		iwm->conf.frag_threshold = wiphy->frag_threshold;
411bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
412b63b0ea2c18bba44c934ec619ba47488553c3aa3Samuel Ortiz		ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
413bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi					     CFG_FRAG_THRESHOLD,
414bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi					     iwm->conf.frag_threshold);
415bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		if (ret < 0)
416bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi			return ret;
417bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
418bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
419bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	return 0;
420bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}
421bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
422bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
423bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi				  struct cfg80211_ibss_params *params)
424bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{
425bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
426bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct ieee80211_channel *chan = params->channel;
427bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
428bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (!test_bit(IWM_STATUS_READY, &iwm->status))
429bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return -EIO;
430bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
43103d1a62c1fb10fe00cfc5cb7f4496d8d6d0e7660Zhu Yi	/* UMAC doesn't support creating or joining an IBSS network
43203d1a62c1fb10fe00cfc5cb7f4496d8d6d0e7660Zhu Yi	 * with specified bssid. */
433bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (params->bssid)
434bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return -EOPNOTSUPP;
435bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
436bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
437bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	iwm->umac_profile->ibss.band = chan->band;
438bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	iwm->umac_profile->ibss.channel = iwm->channel;
439bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	iwm->umac_profile->ssid.ssid_len = params->ssid_len;
440bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
441bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
442bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	return iwm_send_mlme_profile(iwm);
443bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}
444bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
445bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
446bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{
447bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
448bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
449bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (iwm->umac_profile_active)
450bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return iwm_invalidate_mlme_profile(iwm);
451bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
452bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	return 0;
453bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}
454bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
4559967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortizstatic int iwm_set_auth_type(struct iwm_priv *iwm,
4569967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz			     enum nl80211_auth_type sme_auth_type)
4579967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz{
4589967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	u8 *auth_type = &iwm->umac_profile->sec.auth_type;
4599967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
4609967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	switch (sme_auth_type) {
4619967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	case NL80211_AUTHTYPE_AUTOMATIC:
4629967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	case NL80211_AUTHTYPE_OPEN_SYSTEM:
4639967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
4649967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		*auth_type = UMAC_AUTH_TYPE_OPEN;
4659967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		break;
4669967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	case NL80211_AUTHTYPE_SHARED_KEY:
4679967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		if (iwm->umac_profile->sec.flags &
4689967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		    (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
4699967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz			IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
4709967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz			*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
4719967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		} else {
4729967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz			IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
4739967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz			*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
4749967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		}
4759967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
4769967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		break;
4779967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	default:
4789967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
4799967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return -ENOTSUPP;
4809967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	}
4819967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
4829967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	return 0;
4839967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz}
4849967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
4859967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortizstatic int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
4869967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz{
487554503f8c9e11cbea92b7cf1e31f7e4d93ad4492Zhu Yi	IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version);
488554503f8c9e11cbea92b7cf1e31f7e4d93ad4492Zhu Yi
4899967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (!wpa_version) {
4909967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
4919967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return 0;
4929967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	}
4939967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
4946a79c9f62a87e39a265f9b855911fbc1f094ded0Samuel Ortiz	if (wpa_version & NL80211_WPA_VERSION_1)
4956a79c9f62a87e39a265f9b855911fbc1f094ded0Samuel Ortiz		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
4966a79c9f62a87e39a265f9b855911fbc1f094ded0Samuel Ortiz
4979967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (wpa_version & NL80211_WPA_VERSION_2)
4989967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
4999967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5009967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	return 0;
5019967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz}
5029967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5039967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortizstatic int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
5049967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz{
5059967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
5069967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		&iwm->umac_profile->sec.mcast_cipher;
5079967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5089967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (!cipher) {
5099967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		*profile_cipher = UMAC_CIPHER_TYPE_NONE;
5109967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return 0;
5119967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	}
5129967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
513554503f8c9e11cbea92b7cf1e31f7e4d93ad4492Zhu Yi	IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm',
514554503f8c9e11cbea92b7cf1e31f7e4d93ad4492Zhu Yi		     cipher);
515554503f8c9e11cbea92b7cf1e31f7e4d93ad4492Zhu Yi
5169967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	switch (cipher) {
5179967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	case IW_AUTH_CIPHER_NONE:
5189967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		*profile_cipher = UMAC_CIPHER_TYPE_NONE;
5199967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		break;
5209967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	case WLAN_CIPHER_SUITE_WEP40:
5219967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		*profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
5229967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		break;
5239967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	case WLAN_CIPHER_SUITE_WEP104:
5249967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		*profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
5259967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		break;
5269967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	case WLAN_CIPHER_SUITE_TKIP:
5279967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		*profile_cipher = UMAC_CIPHER_TYPE_TKIP;
5289967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		break;
5299967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	case WLAN_CIPHER_SUITE_CCMP:
5309967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		*profile_cipher = UMAC_CIPHER_TYPE_CCMP;
5319967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		break;
5329967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	default:
5339967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
5349967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return -ENOTSUPP;
5359967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	}
5369967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5379967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	return 0;
5389967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz}
5399967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5409967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortizstatic int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
5419967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz{
5429967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	u8 *auth_type = &iwm->umac_profile->sec.auth_type;
5439967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5449967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
5459967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5469967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (key_mgt == WLAN_AKM_SUITE_8021X)
5479967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		*auth_type = UMAC_AUTH_TYPE_8021X;
5489967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	else if (key_mgt == WLAN_AKM_SUITE_PSK) {
5499967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		if (iwm->umac_profile->sec.flags &
5509967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		    (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
5519967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz			*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
5529967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		else
5539967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz			*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
5549967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	} else {
5559967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
5569967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return -EINVAL;
5579967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	}
5589967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5599967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	return 0;
5609967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz}
5619967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5629967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5639967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortizstatic int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
5649967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz				 struct cfg80211_connect_params *sme)
5659967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz{
5669967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
5679967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	struct ieee80211_channel *chan = sme->channel;
568b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	struct key_params key_param;
5699967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	int ret;
5709967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5719967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (!test_bit(IWM_STATUS_READY, &iwm->status))
5729967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return -EIO;
5739967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5749967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (!sme->ssid)
5759967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return -EINVAL;
5769967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
577ae73abf2350de7cbfc5c46a936f4d2a532b36679Zhu Yi	if (iwm->umac_profile_active) {
578ae73abf2350de7cbfc5c46a936f4d2a532b36679Zhu Yi		ret = iwm_invalidate_mlme_profile(iwm);
579ae73abf2350de7cbfc5c46a936f4d2a532b36679Zhu Yi		if (ret) {
580ae73abf2350de7cbfc5c46a936f4d2a532b36679Zhu Yi			IWM_ERR(iwm, "Couldn't invalidate profile\n");
581ae73abf2350de7cbfc5c46a936f4d2a532b36679Zhu Yi			return ret;
582ae73abf2350de7cbfc5c46a936f4d2a532b36679Zhu Yi		}
583ae73abf2350de7cbfc5c46a936f4d2a532b36679Zhu Yi	}
584ae73abf2350de7cbfc5c46a936f4d2a532b36679Zhu Yi
5859967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (chan)
5869967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		iwm->channel =
5879967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz			ieee80211_frequency_to_channel(chan->center_freq);
5889967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5899967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
5909967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
5919967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
5929967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (sme->bssid) {
5939967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
5949967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
5959967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		iwm->umac_profile->bss_num = 1;
5969967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	} else {
5979967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
5989967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		iwm->umac_profile->bss_num = 0;
5999967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	}
6009967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
601554503f8c9e11cbea92b7cf1e31f7e4d93ad4492Zhu Yi	ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
6029967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (ret < 0)
6039967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return ret;
6049967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
605554503f8c9e11cbea92b7cf1e31f7e4d93ad4492Zhu Yi	ret = iwm_set_auth_type(iwm, sme->auth_type);
6069967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (ret < 0)
6079967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return ret;
6089967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
6099967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (sme->crypto.n_ciphers_pairwise) {
6109967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
6119967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz				     true);
6129967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		if (ret < 0)
6139967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz			return ret;
6149967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	}
6159967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
6169967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
6179967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (ret < 0)
6189967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		return ret;
6199967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
6209967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (sme->crypto.n_akm_suites) {
6219967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
6229967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz		if (ret < 0)
6239967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz			return ret;
6249967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	}
6259967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
626b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	/*
627b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	 * We save the WEP key in case we want to do shared authentication.
628b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	 * We have to do it so because UMAC will assert whenever it gets a
629b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	 * key before a profile.
630b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	 */
631b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	if (sme->key) {
632b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		key_param.key = kmemdup(sme->key, sme->key_len, GFP_KERNEL);
633b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		if (key_param.key == NULL)
634b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz			return -ENOMEM;
635b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		key_param.key_len = sme->key_len;
636b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		key_param.seq_len = 0;
637b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		key_param.cipher = sme->crypto.ciphers_pairwise[0];
638b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz
639b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		ret = iwm_key_init(&iwm->keys[sme->key_idx], sme->key_idx,
640b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz				   NULL, &key_param);
641b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		kfree(key_param.key);
642b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		if (ret < 0) {
643b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz			IWM_ERR(iwm, "Invalid key_params\n");
644b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz			return ret;
645b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		}
646b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz
647b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		iwm->default_key = sme->key_idx;
648b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	}
649b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz
650a82aedbf1b043f7a7474aa9b6d223104ac51827aSamuel Ortiz	/* WPA and open AUTH type from wpa_s means WPS (a.k.a. WSC) */
651a82aedbf1b043f7a7474aa9b6d223104ac51827aSamuel Ortiz	if ((iwm->umac_profile->sec.flags &
652a82aedbf1b043f7a7474aa9b6d223104ac51827aSamuel Ortiz	     (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) &&
653a82aedbf1b043f7a7474aa9b6d223104ac51827aSamuel Ortiz	    iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN) {
654a82aedbf1b043f7a7474aa9b6d223104ac51827aSamuel Ortiz			iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WSC_ON_MSK;
655a82aedbf1b043f7a7474aa9b6d223104ac51827aSamuel Ortiz	}
656a82aedbf1b043f7a7474aa9b6d223104ac51827aSamuel Ortiz
657b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	ret = iwm_send_mlme_profile(iwm);
658b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz
659b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK ||
660b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	    sme->key == NULL)
661b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		return ret;
662b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz
663b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	/*
664b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	 * We want to do shared auth.
665b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	 * We need to actually set the key we previously cached,
666b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	 * and then tell the UMAC it's the default one.
667b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	 * That will trigger the auth+assoc UMAC machinery, and again,
668b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	 * this must be done after setting the profile.
669b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	 */
670b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	ret = iwm_set_key(iwm, 0, &iwm->keys[sme->key_idx]);
671b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	if (ret < 0)
672b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz		return ret;
673b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz
674b90a5c9561d3f75f906a84613cc0071121143fb6Samuel Ortiz	return iwm_set_tx_key(iwm, iwm->default_key);
6759967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz}
6769967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
6779967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortizstatic int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
6789967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz				   u16 reason_code)
6799967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz{
6809967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
6819967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
6829967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
6839967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
6849967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	if (iwm->umac_profile_active)
685de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi		iwm_invalidate_mlme_profile(iwm);
6869967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
6879967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	return 0;
6889967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz}
6899967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz
690257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yistatic int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
691fa61cf70a6ae1089e459e4b59b2e8d8e90d8535eJuuso Oikarinen				    enum nl80211_tx_power_setting type, int mbm)
692257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi{
69388e6195a911bce85adcc14e8377aa619e8054ab2Samuel Ortiz	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
69488e6195a911bce85adcc14e8377aa619e8054ab2Samuel Ortiz	int ret;
69588e6195a911bce85adcc14e8377aa619e8054ab2Samuel Ortiz
696257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi	switch (type) {
697fa61cf70a6ae1089e459e4b59b2e8d8e90d8535eJuuso Oikarinen	case NL80211_TX_POWER_AUTOMATIC:
698257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi		return 0;
699fa61cf70a6ae1089e459e4b59b2e8d8e90d8535eJuuso Oikarinen	case NL80211_TX_POWER_FIXED:
700fa61cf70a6ae1089e459e4b59b2e8d8e90d8535eJuuso Oikarinen		if (mbm < 0 || (mbm % 100))
701fa61cf70a6ae1089e459e4b59b2e8d8e90d8535eJuuso Oikarinen			return -EOPNOTSUPP;
702fa61cf70a6ae1089e459e4b59b2e8d8e90d8535eJuuso Oikarinen
703fe19176ea46db572f0dc2df8bfe1dc5d8751ab9eSamuel Ortiz		if (!test_bit(IWM_STATUS_READY, &iwm->status))
704fe19176ea46db572f0dc2df8bfe1dc5d8751ab9eSamuel Ortiz			return 0;
705fe19176ea46db572f0dc2df8bfe1dc5d8751ab9eSamuel Ortiz
70688e6195a911bce85adcc14e8377aa619e8054ab2Samuel Ortiz		ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
707fa61cf70a6ae1089e459e4b59b2e8d8e90d8535eJuuso Oikarinen					      CFG_TX_PWR_LIMIT_USR,
708fa61cf70a6ae1089e459e4b59b2e8d8e90d8535eJuuso Oikarinen					      MBM_TO_DBM(mbm) * 2);
70988e6195a911bce85adcc14e8377aa619e8054ab2Samuel Ortiz		if (ret < 0)
71088e6195a911bce85adcc14e8377aa619e8054ab2Samuel Ortiz			return ret;
71188e6195a911bce85adcc14e8377aa619e8054ab2Samuel Ortiz
71288e6195a911bce85adcc14e8377aa619e8054ab2Samuel Ortiz		return iwm_tx_power_trigger(iwm);
713257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi	default:
714fe19176ea46db572f0dc2df8bfe1dc5d8751ab9eSamuel Ortiz		IWM_ERR(iwm, "Unsupported power type: %d\n", type);
715257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi		return -EOPNOTSUPP;
716257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi	}
717257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi
718257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi	return 0;
719257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi}
720257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi
721257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yistatic int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
722257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi{
723257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
724257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi
72588e6195a911bce85adcc14e8377aa619e8054ab2Samuel Ortiz	*dbm = iwm->txpower >> 1;
726257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi
727257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi	return 0;
728257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi}
729257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi
730bc92afd92088ab41223383cc6863ab4792533c54Johannes Bergstatic int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
731bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg				       struct net_device *dev,
732bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg				       bool enabled, int timeout)
733bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg{
734bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
735bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg	u32 power_index;
736bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg
737bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg	if (enabled)
738bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg		power_index = IWM_POWER_INDEX_DEFAULT;
739bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg	else
740bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg		power_index = IWM_POWER_INDEX_MIN;
741bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg
742bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg	if (power_index == iwm->conf.power_index)
743bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg		return 0;
744bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg
745bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg	iwm->conf.power_index = power_index;
746bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg
747bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg	return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
748bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg				       CFG_POWER_INDEX, iwm->conf.power_index);
749bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg}
750bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg
751d281fd461dcb9b3d0dc46180bf6e90da3913079dZhu Yistatic int iwm_cfg80211_set_pmksa(struct wiphy *wiphy,
752d281fd461dcb9b3d0dc46180bf6e90da3913079dZhu Yi				  struct net_device *netdev,
753d281fd461dcb9b3d0dc46180bf6e90da3913079dZhu Yi				  struct cfg80211_pmksa *pmksa)
7549bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz{
7559bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
7569bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz
7579bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD);
7589bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz}
7599bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz
760d281fd461dcb9b3d0dc46180bf6e90da3913079dZhu Yistatic int iwm_cfg80211_del_pmksa(struct wiphy *wiphy,
761d281fd461dcb9b3d0dc46180bf6e90da3913079dZhu Yi				  struct net_device *netdev,
762d281fd461dcb9b3d0dc46180bf6e90da3913079dZhu Yi				  struct cfg80211_pmksa *pmksa)
7639bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz{
7649bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
7659bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz
7669bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL);
7679bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz}
7689bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz
769d281fd461dcb9b3d0dc46180bf6e90da3913079dZhu Yistatic int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy,
770d281fd461dcb9b3d0dc46180bf6e90da3913079dZhu Yi				    struct net_device *netdev)
7719bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz{
7729bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
7739bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	struct cfg80211_pmksa pmksa;
7749bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz
7759bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
7769bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz
7779bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	return iwm_send_pmkid_update(iwm, &pmksa, IWM_CMD_PMKID_FLUSH);
7789bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz}
7799bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz
7809bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz
781bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic struct cfg80211_ops iwm_cfg80211_ops = {
782bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.change_virtual_intf = iwm_cfg80211_change_iface,
78313e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	.add_key = iwm_cfg80211_add_key,
78413e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	.get_key = iwm_cfg80211_get_key,
78513e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	.del_key = iwm_cfg80211_del_key,
78613e0fe70960e95cdea89b71aa3d046ec71efac8cSamuel Ortiz	.set_default_key = iwm_cfg80211_set_default_key,
7879967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	.get_station = iwm_cfg80211_get_station,
788bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.scan = iwm_cfg80211_scan,
789bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
7909967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	.connect = iwm_cfg80211_connect,
7919967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz	.disconnect = iwm_cfg80211_disconnect,
792bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.join_ibss = iwm_cfg80211_join_ibss,
793bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	.leave_ibss = iwm_cfg80211_leave_ibss,
794257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi	.set_tx_power = iwm_cfg80211_set_txpower,
795257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi	.get_tx_power = iwm_cfg80211_get_txpower,
796bc92afd92088ab41223383cc6863ab4792533c54Johannes Berg	.set_power_mgmt = iwm_cfg80211_set_power_mgmt,
7979bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	.set_pmksa = iwm_cfg80211_set_pmksa,
7989bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	.del_pmksa = iwm_cfg80211_del_pmksa,
7999bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	.flush_pmksa = iwm_cfg80211_flush_pmksa,
800bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi};
801bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
80249b7772776359b8306ce740bfc52d32b344adc83Zhu Yistatic const u32 cipher_suites[] = {
80349b7772776359b8306ce740bfc52d32b344adc83Zhu Yi	WLAN_CIPHER_SUITE_WEP40,
80449b7772776359b8306ce740bfc52d32b344adc83Zhu Yi	WLAN_CIPHER_SUITE_WEP104,
80549b7772776359b8306ce740bfc52d32b344adc83Zhu Yi	WLAN_CIPHER_SUITE_TKIP,
80649b7772776359b8306ce740bfc52d32b344adc83Zhu Yi	WLAN_CIPHER_SUITE_CCMP,
80749b7772776359b8306ce740bfc52d32b344adc83Zhu Yi};
80849b7772776359b8306ce740bfc52d32b344adc83Zhu Yi
809bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistruct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
810bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{
811bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	int ret = 0;
812bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct wireless_dev *wdev;
813bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
814bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	/*
815bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 * We're trying to have the following memory
816bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 * layout:
817bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 *
818bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 * +-------------------------+
819bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 * | struct wiphy	     |
820bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 * +-------------------------+
821bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 * | struct iwm_priv         |
822bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 * +-------------------------+
823bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 * | bus private data        |
824bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 * | (e.g. iwm_priv_sdio)    |
825bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 * +-------------------------+
826bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 *
827bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	 */
828bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
829bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
830bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (!wdev) {
831bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		dev_err(dev, "Couldn't allocate wireless device\n");
832bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return ERR_PTR(-ENOMEM);
833bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
834bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
835bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wdev->wiphy = wiphy_new(&iwm_cfg80211_ops,
836bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi				sizeof(struct iwm_priv) + sizeof_bus);
837bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (!wdev->wiphy) {
838bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		dev_err(dev, "Couldn't allocate wiphy device\n");
839bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		ret = -ENOMEM;
840bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		goto out_err_new;
841bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
842bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
843bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	set_wiphy_dev(wdev->wiphy, dev);
844bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
8459bf22f2c4607dbb68beb26153d83fa52b82e2d2fSamuel Ortiz	wdev->wiphy->max_num_pmkids = UMAC_MAX_NUM_PMKIDS;
846bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
847bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi				       BIT(NL80211_IFTYPE_ADHOC);
848bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz;
849bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
850bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
851bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
85249b7772776359b8306ce740bfc52d32b344adc83Zhu Yi	wdev->wiphy->cipher_suites = cipher_suites;
85349b7772776359b8306ce740bfc52d32b344adc83Zhu Yi	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
85449b7772776359b8306ce740bfc52d32b344adc83Zhu Yi
855bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	ret = wiphy_register(wdev->wiphy);
856bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (ret < 0) {
857bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		dev_err(dev, "Couldn't register wiphy device\n");
858bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		goto out_err_register;
859bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	}
860bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
861bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	return wdev;
862bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
863bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi out_err_register:
864bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wiphy_free(wdev->wiphy);
865bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
866bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi out_err_new:
867bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	kfree(wdev);
868bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
869bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	return ERR_PTR(ret);
870bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}
871bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
872bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yivoid iwm_wdev_free(struct iwm_priv *iwm)
873bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{
874bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	struct wireless_dev *wdev = iwm_to_wdev(iwm);
875bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
876bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	if (!wdev)
877bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi		return;
878bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi
879bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wiphy_unregister(wdev->wiphy);
880bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	wiphy_free(wdev->wiphy);
881bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi	kfree(wdev);
882bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}
883