Skip to contentSkip to conversation

iwmc3200wifi updates

PATCH New Samuel Ortiz 1 participant 12 messages Jun 15, 2009 Networking drivers (wireless)

lore
Share & tools
lore
#0 lore raw

v2 cover iwmc3200wifi updates

Hi John,

Here go some updates for the iwmc3200wifi driver.
Some of those patches are bug fixes and we'd like them to eventually make it to 2.6.31. The rest are targeted at wireless-testing inclusion. I tried to set an explicit subject line to let you clearly understand where we'd like each of them to land, please let me know if that's not the case.

Changes:
v2: Removed patch #1 from the previous patch set.
With patch #3 (#2 on patch set v2), we are actually registering the netdev _after_ the SDIO bus is really ready.

Samuel Ortiz (4):
iwmc3200wifi: invalidate keys when changing the BSSID
iwmc3200wifi: handling wifi_if_ntfy responses
iwmc3200wifi: cfg80211 key hooks implemetation
iwmc3200wifi: cache keys when interface is down

Zhu Yi (7):
iwmc3200wifi: check for iwm_priv_init error
iwmc3200wifi: add iwm_if_add and iwm_if_remove
iwmc3200wifi: fix potential kernel oops on module removal
iwmc3200wifi: add a mutex to protect iwm_reset_worker
iwmc3200wifi: change coexist periodic calibration flag
iwmc3200wifi: remove select LIB80211 from Kconfig
iwmc3200wifi: rfkill cleanup

 drivers/net/wireless/iwmc3200wifi/Kconfig    |    1 -
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |  204 +++++++++++++++++
 drivers/net/wireless/iwmc3200wifi/commands.c |  116 +++++------
 drivers/net/wireless/iwmc3200wifi/commands.h |    7 +-
 drivers/net/wireless/iwmc3200wifi/iwm.h      |   28 ++--
 drivers/net/wireless/iwmc3200wifi/main.c     |   89 ++++++--
 drivers/net/wireless/iwmc3200wifi/netdev.c   |   72 ++++---
 drivers/net/wireless/iwmc3200wifi/rx.c       |   27 ++-
 drivers/net/wireless/iwmc3200wifi/sdio.c     |   17 +-
 drivers/net/wireless/iwmc3200wifi/umac.h     |    2 +
 drivers/net/wireless/iwmc3200wifi/wext.c     |  305 +++-----------------------
 11 files changed, 443 insertions(+), 425 deletions(-)
#1 lore raw

PATCH v2 1/11 iwmc3200wifi: check for iwm_priv_init error

From: Zhu Yi <[email protected]>

We need to check for iwm_priv_init() errors and do proper cleanups. Otherwise we may fail to catch the create_singlethread_workqueue() error which will cause a kernel oops when destroy_workqueue() later.

---
 drivers/net/wireless/iwmc3200wifi/iwm.h    |    1 +
 drivers/net/wireless/iwmc3200wifi/main.c   |   10 ++++++++++
 drivers/net/wireless/iwmc3200wifi/netdev.c |   19 ++++++++++++-------
 3 files changed, 23 insertions(+), 7 deletions(-)
drivers/net/wireless/iwmc3200wifi/iwm.h +1 -0
index 635c16e..2237448 100644
@@ -317,6 +317,7 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
 void iwm_if_free(struct iwm_priv *iwm);
 int iwm_mode_to_nl80211_iftype(int mode);
 int iwm_priv_init(struct iwm_priv *iwm);
+void iwm_priv_deinit(struct iwm_priv *iwm);
 void iwm_reset(struct iwm_priv *iwm);
 void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
 			      struct iwm_umac_notif_alive *alive);
drivers/net/wireless/iwmc3200wifi/main.c +10 -0
index 6a2640f..4d3c423 100644
@@ -219,6 +219,16 @@ int iwm_priv_init(struct iwm_priv *iwm)
 	return 0;
 }
 
+void iwm_priv_deinit(struct iwm_priv *iwm)
+{
+	int i;
+
+	for (i = 0; i < IWM_TX_QUEUES; i++)
+		destroy_workqueue(iwm->txq[i].wq);
+
+	destroy_workqueue(iwm->rx_wq);
+}
+
 /*
  * We reset all the structures, and we reset the UMAC.
  * After calling this routine, you're expected to reload
drivers/net/wireless/iwmc3200wifi/netdev.c +12 -7
index 68e2c3b..88dd826 100644
@@ -114,14 +114,20 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
 	iwm = wdev_to_iwm(wdev);
 	iwm->bus_ops = if_ops;
 	iwm->wdev = wdev;
-	iwm_priv_init(iwm);
+
+	ret = iwm_priv_init(iwm);
+	if (ret) {
+		dev_err(dev, "failed to init iwm_priv\n");
+		goto out_wdev;
+	}
+
 	wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode);
 
 	ndev = alloc_netdev_mq(0, "wlan%d", ether_setup,
 			       IWM_TX_QUEUES);
 	if (!ndev) {
 		dev_err(dev, "no memory for network device instance\n");
-		goto out_wdev;
+		goto out_priv;
 	}
 
 	ndev->netdev_ops = &iwm_netdev_ops;
@@ -141,6 +147,9 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
  out_ndev:
 	free_netdev(ndev);
 
+ out_priv:
+	iwm_priv_deinit(iwm);
+
  out_wdev:
 	iwm_wdev_free(iwm);
 	return ERR_PTR(ret);
@@ -148,15 +157,11 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
 
 void iwm_if_free(struct iwm_priv *iwm)
 {
-	int i;
-
 	if (!iwm_to_ndev(iwm))
 		return;
 
 	unregister_netdev(iwm_to_ndev(iwm));
 	free_netdev(iwm_to_ndev(iwm));
 	iwm_wdev_free(iwm);
-	destroy_workqueue(iwm->rx_wq);
-	for (i = 0; i < IWM_TX_QUEUES; i++)
-		destroy_workqueue(iwm->txq[i].wq);
+	iwm_priv_deinit(iwm);
 }
Signature · 1 line
1.6.3.1
#2 lore raw

PATCH v2 2/11 iwmc3200wifi: add iwm_if_add and iwm_if_remove

From: Zhu Yi <[email protected]>

We used to do alloc_netdev and register_netdev at the same time in iwm_if_alloc. But some bus related structures will only be initialized after iwm_priv is allocated. This caused a race condition that the netdev might be registered earlier. The patch adds iwm_if_add and iwm_if_remove so that the bus layer could register the device after all initialization is done.

---
 drivers/net/wireless/iwmc3200wifi/iwm.h    |    2 +
 drivers/net/wireless/iwmc3200wifi/netdev.c |   32 +++++++++++++++++----------
 drivers/net/wireless/iwmc3200wifi/sdio.c   |    9 +++++++
 3 files changed, 31 insertions(+), 12 deletions(-)
drivers/net/wireless/iwmc3200wifi/iwm.h +2 -0
index 2237448..4aa0ad1 100644
@@ -315,6 +315,8 @@ extern const struct iw_handler_def iwm_iw_handler_def;
 void *iwm_if_alloc(int sizeof_bus, struct device *dev,
 		   struct iwm_if_ops *if_ops);
 void iwm_if_free(struct iwm_priv *iwm);
+int iwm_if_add(struct iwm_priv *iwm);
+void iwm_if_remove(struct iwm_priv *iwm);
 int iwm_mode_to_nl80211_iftype(int mode);
 int iwm_priv_init(struct iwm_priv *iwm);
 void iwm_priv_deinit(struct iwm_priv *iwm);
drivers/net/wireless/iwmc3200wifi/netdev.c +20 -12
index 88dd826..aaa20c6 100644
@@ -123,8 +123,7 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
 
 	wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode);
 
-	ndev = alloc_netdev_mq(0, "wlan%d", ether_setup,
-			       IWM_TX_QUEUES);
+	ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
 	if (!ndev) {
 		dev_err(dev, "no memory for network device instance\n");
 		goto out_priv;
@@ -134,19 +133,10 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
 	ndev->wireless_handlers = &iwm_iw_handler_def;
 	ndev->ieee80211_ptr = wdev;
 	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
-	ret = register_netdev(ndev);
-	if (ret < 0) {
-		dev_err(dev, "Failed to register netdev: %d\n", ret);
-		goto out_ndev;
-	}
-
 	wdev->netdev = ndev;
 
 	return iwm;
 
- out_ndev:
-	free_netdev(ndev);
-
  out_priv:
 	iwm_priv_deinit(iwm);
 
@@ -160,8 +150,26 @@ void iwm_if_free(struct iwm_priv *iwm)
 	if (!iwm_to_ndev(iwm))
 		return;
 
-	unregister_netdev(iwm_to_ndev(iwm));
 	free_netdev(iwm_to_ndev(iwm));
 	iwm_wdev_free(iwm);
 	iwm_priv_deinit(iwm);
 }
+
+int iwm_if_add(struct iwm_priv *iwm)
+{
+	struct net_device *ndev = iwm_to_ndev(iwm);
+	int ret;
+
+	ret = register_netdev(ndev);
+	if (ret < 0) {
+		dev_err(&ndev->dev, "Failed to register netdev: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+void iwm_if_remove(struct iwm_priv *iwm)
+{
+	unregister_netdev(iwm_to_ndev(iwm));
+}
drivers/net/wireless/iwmc3200wifi/sdio.c +9 -0
index b54da67..c040571 100644
@@ -454,10 +454,18 @@ static int iwm_sdio_probe(struct sdio_func *func,
 
 	INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker);
 
+	ret = iwm_if_add(iwm);
+	if (ret) {
+		dev_err(dev, "add SDIO interface failed\n");
+		goto destroy_wq;
+	}
+
 	dev_info(dev, "IWM SDIO probe\n");
 
 	return 0;
 
+ destroy_wq:
+	destroy_workqueue(hw->isr_wq);
  debugfs_exit:
 	iwm_debugfs_exit(iwm);
  if_free:
@@ -472,6 +480,7 @@ static void iwm_sdio_remove(struct sdio_func *func)
 	struct device *dev = &func->dev;
 
 	iwm_debugfs_exit(iwm);
+	iwm_if_remove(iwm);
 	iwm_if_free(iwm);
 	destroy_workqueue(hw->isr_wq);
 
Signature · 1 line
1.6.3.1
#3 lore raw

PATCH v2 3/11 iwmc3200wifi: fix potential kernel oops on module removal

In reply to Samuel Ortiz

From: Zhu Yi <[email protected]>

The iwm_if_free() is called before destroy_workqueue for isr_wq on device remove method. But if there is still some pending work in the isr_wq, the required data structures are already freed at this point. This leeds a kernel oops. The patch fixes this problem by moving iwm_if_free after destroy_workqueue.

---
 drivers/net/wireless/iwmc3200wifi/sdio.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/iwmc3200wifi/sdio.c +2 -2
index c040571..9166818 100644
@@ -479,10 +479,10 @@ static void iwm_sdio_remove(struct sdio_func *func)
 	struct iwm_priv *iwm = hw_to_iwm(hw);
 	struct device *dev = &func->dev;
 
-	iwm_debugfs_exit(iwm);
 	iwm_if_remove(iwm);
-	iwm_if_free(iwm);
 	destroy_workqueue(hw->isr_wq);
+	iwm_debugfs_exit(iwm);
+	iwm_if_free(iwm);
 
 	sdio_set_drvdata(func, NULL);
 
Signature · 1 line
1.6.3.1
#4 lore raw

PATCH v2 4/11 iwmc3200wifi: add a mutex to protect iwm_reset_worker

From: Zhu Yi <[email protected]>

The patch adds a mutex to protect the iwm_reset_worker against netdev ndo_open and ndo_stop because all of them call iwm_up and iwm_down in the implementation. Note the latter two are already protected by rtnl. So if iwm_reset_worker is not required in the future, the mutex can also be removed.

---
 drivers/net/wireless/iwmc3200wifi/iwm.h  |    1 +
 drivers/net/wireless/iwmc3200wifi/main.c |   54 ++++++++++++++++++++++++++---
 2 files changed, 49 insertions(+), 6 deletions(-)
drivers/net/wireless/iwmc3200wifi/iwm.h +1 -0
index 4aa0ad1..77c339f 100644
@@ -288,6 +288,7 @@ struct iwm_priv {
 	u8 *eeprom;
 	struct timer_list watchdog;
 	struct work_struct reset_worker;
+	struct mutex mutex;
 	struct rfkill *rfkill;
 
 	char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
drivers/net/wireless/iwmc3200wifi/main.c +48 -6

113 lines not on this page · raw message

Signature · 1 line
1.6.3.1
#5 lore raw

PATCH v2 5/11 iwmc3200wifi: invalidate keys when changing the BSSID

From: Samuel Ortiz <[email protected]>

While associated, we have to invalidate our key cache if we clear our BSSID through siwap.

---
 drivers/net/wireless/iwmc3200wifi/wext.c |   19 ++++++++++++++++++-
 1 files changed, 18 insertions(+), 1 deletions(-)
drivers/net/wireless/iwmc3200wifi/wext.c +18 -1
index 584c94d..8891949 100644
@@ -82,6 +82,7 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
 			  struct sockaddr *ap_addr, char *extra)
 {
 	struct iwm_priv *iwm = ndev_to_iwm(dev);
+	int ret;
 
 	if (iwm->conf.mode == UMAC_MODE_IBSS)
 		return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
@@ -104,10 +105,26 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
 	}
 
 	if (iwm->umac_profile_active) {
+		int i;
+
 		if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
 			return 0;
 
-		iwm_invalidate_mlme_profile(iwm);
+		/*
+		 * If we're clearing the BSSID, and we're associated,
+		 * we have to clear the keys as they're no longer valid.
+		 */
+		if (is_zero_ether_addr(ap_addr->sa_data)) {
+			for (i = 0; i < IWM_NUM_KEYS; i++)
+				iwm->keys[i].in_use = 0;
+
+		}
+
+		ret = iwm_invalidate_mlme_profile(iwm);
+		if (ret < 0) {
+			IWM_ERR(iwm, "Couldn't invalidate profile\n");
+			return ret;
+		}
 	}
 
 	if (iwm->umac_profile->ssid.ssid_len)
Signature · 1 line
1.6.3.1
#6 lore raw

PATCH v2 6/11 iwmc3200wifi: handling wifi_if_ntfy responses

From: Samuel Ortiz <[email protected]>

When we're calling iwm_send_wifi_if_cmd() with the resp flag set, we're currently waiting on the mlme queue, waiting for some flags here and there to show up.
This patch adds a wifi_ntfy bitmap, and when we're sending a wifi_if command expecting an answers, we wait synchronously for it to show up, on a dedicated queue. The wifi_ntfy bit is set when we receive the corresponding answer.

---
 drivers/net/wireless/iwmc3200wifi/commands.c |   31 +++++++++++++++-----------
 drivers/net/wireless/iwmc3200wifi/iwm.h      |    3 ++
 drivers/net/wireless/iwmc3200wifi/main.c     |    1 +
 drivers/net/wireless/iwmc3200wifi/rx.c       |    9 ++++++-
 drivers/net/wireless/iwmc3200wifi/umac.h     |    2 +
 5 files changed, 31 insertions(+), 15 deletions(-)
drivers/net/wireless/iwmc3200wifi/commands.c +18 -13
index 834a7f5..337a884 100644
@@ -70,14 +70,28 @@ static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm,
 int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
 			 bool resp)
 {
+	struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload;
 	struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
 	struct iwm_umac_cmd umac_cmd;
+	int ret;
+	u8 oid = hdr->oid;
 
 	umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
 	umac_cmd.resp = resp;
 
-	return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
-				     payload, payload_size);
+	ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
+				    payload, payload_size);
+
+	if (resp) {
+		ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue,
+				   test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
+				   3 * HZ);
+
+		if (!ret)
+			ret = -EBUSY;
+	}
+
+	return ret;
 }
 
 static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
@@ -746,14 +760,6 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
 		return ret;
 	}
 
-	/* Wait for the profile to be active */
-	ret = wait_event_interruptible_timeout(iwm->mlme_queue,
-					       iwm->umac_profile_active == 1,
-					       3 * HZ);
-	if (!ret)
-		return -EBUSY;
-
-
 	for (i = 0; i < IWM_NUM_KEYS; i++)
 		if (iwm->keys[i].in_use) {
 			int default_key = 0;
@@ -778,8 +784,8 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
 
 int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
 {
-	int ret;
 	struct iwm_umac_invalidate_profile invalid;
+	int ret;
 
 	invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
 	invalid.hdr.buf_size =
@@ -793,8 +799,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
 		return ret;
 
 	ret = wait_event_interruptible_timeout(iwm->mlme_queue,
-				 (iwm->umac_profile_active == 0),
-					       2 * HZ);
+				(iwm->umac_profile_active == 0), 2 * HZ);
 	if (!ret)
 		return -EBUSY;
 
drivers/net/wireless/iwmc3200wifi/iwm.h +3 -0
index 77c339f..d8d4ae2 100644
@@ -278,6 +278,9 @@ struct iwm_priv {
 	struct iwm_key keys[IWM_NUM_KEYS];
 	struct iwm_key *default_key;
 
+	DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX);
+	wait_queue_head_t wifi_ntfy_queue;
+
 	wait_queue_head_t mlme_queue;
 
 	struct iw_statistics wstats;
drivers/net/wireless/iwmc3200wifi/main.c +1 -0
index 8be206d..8448722 100644
@@ -191,6 +191,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
 	INIT_LIST_HEAD(&iwm->pending_notif);
 	init_waitqueue_head(&iwm->notif_queue);
 	init_waitqueue_head(&iwm->nonwifi_queue);
+	init_waitqueue_head(&iwm->wifi_ntfy_queue);
 	init_waitqueue_head(&iwm->mlme_queue);
 	memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf));
 	spin_lock_init(&iwm->tx_credit.lock);
drivers/net/wireless/iwmc3200wifi/rx.c +7 -2
index d73cf96..49a8be7 100644
@@ -993,12 +993,17 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
 			(struct iwm_umac_wifi_if *)cmd->buf.payload;
 
 	IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
-		    "oid is %d\n", hdr->oid);
+		    "oid is 0x%x\n", hdr->oid);
+
+	if (hdr->oid <= WIFI_IF_NTFY_MAX) {
+		set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
+		wake_up_interruptible(&iwm->wifi_ntfy_queue);
+	} else
+		return -EINVAL;
 
 	switch (hdr->oid) {
 	case UMAC_WIFI_IF_CMD_SET_PROFILE:
 		iwm->umac_profile_active = 1;
-		wake_up_interruptible(&iwm->mlme_queue);
 		break;
 	default:
 		break;
drivers/net/wireless/iwmc3200wifi/umac.h +2 -0
index 4a95cce..0af2a3c 100644
@@ -495,6 +495,8 @@ struct iwm_fw_alive_hdr {
 #define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP		0xE8
 #define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP	0xE9
 
+#define WIFI_IF_NTFY_MAX 0xff
+
 /* Notification structures */
 struct iwm_umac_notif_wifi_if {
 	struct iwm_umac_wifi_in_hdr hdr;
Signature · 1 line
1.6.3.1
#7 lore raw

PATCH v2 7/11 iwmc3200wifi: cfg80211 key hooks implemetation

From: Samuel Ortiz <[email protected]>

This patch implements the new cfg80211 privacy related hooks: add/get/set_key and the set_default_key one.
With this implementation we can now call the wext-compat *encode* routines and reduce our own wext code.

---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |  172 ++++++++++++++++
 drivers/net/wireless/iwmc3200wifi/commands.c |   72 +++-----
 drivers/net/wireless/iwmc3200wifi/commands.h |    3 +-
 drivers/net/wireless/iwmc3200wifi/iwm.h      |   14 +-
 drivers/net/wireless/iwmc3200wifi/main.c     |    4 +-
 drivers/net/wireless/iwmc3200wifi/wext.c     |  286 ++------------------------
 6 files changed, 219 insertions(+), 332 deletions(-)
drivers/net/wireless/iwmc3200wifi/cfg80211.c +172 -0
index 96f714e..ad62b20 100644
@@ -23,6 +23,7 @@
 
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/wireless.h>
 #include <linux/ieee80211.h>
 #include <net/cfg80211.h>
@@ -130,6 +131,173 @@ static struct ieee80211_supported_band iwm_band_5ghz = {
 	.n_bitrates = iwm_a_rates_size,
 };
 
+static int iwm_key_init(struct iwm_key *key, u8 key_index,
+			const u8 *mac_addr, struct key_params *params)
+{
+	key->hdr.key_idx = key_index;
+	if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
+		key->hdr.multicast = 1;
+		memset(key->hdr.mac, 0xff, ETH_ALEN);
+	} else {
+		key->hdr.multicast = 0;
+		memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
+	}
+
+	if (params) {
+		if (params->key_len > WLAN_MAX_KEY_LEN ||
+		    params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
+			return -EINVAL;
+
+		key->cipher = params->cipher;
+		key->key_len = params->key_len;
+		key->seq_len = params->seq_len;
+		memcpy(key->key, params->key, key->key_len);
+		memcpy(key->seq, params->seq, key->seq_len);
+	}
+
+	return 0;
+}
+
+static int iwm_reset_profile(struct iwm_priv *iwm)
+{
+	int ret;
+
+	if (!iwm->umac_profile_active)
+		return 0;
+
+	/*
+	 * If there is a current active profile, but no
+	 * default key, it's not worth trying to associate again.
+	 */
+	if (iwm->default_key < 0)
+		return 0;
+
+	/*
+	 * Here we have an active profile, but a key setting changed.
+	 * We thus have to invalidate the current profile, and push the
+	 * new one. Keys will be pushed when association takes place.
+	 */
+	ret = iwm_invalidate_mlme_profile(iwm);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Couldn't invalidate profile\n");
+		return ret;
+	}
+
+	return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
+				u8 key_index, const u8 *mac_addr,
+				struct key_params *params)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(ndev);
+	struct iwm_key *key = &iwm->keys[key_index];
+	int ret;
+
+	IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
+
+	memset(key, 0, sizeof(struct iwm_key));
+	ret = iwm_key_init(key, key_index, mac_addr, params);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Invalid key_params\n");
+		return ret;
+	}
+
+	/*
+	 * The WEP keys can be set before or after setting the essid.
+	 * We need to handle both cases by simply pushing the keys after
+	 * we send the profile.
+	 * If the profile is not set yet (i.e. we're pushing keys before
+	 * the essid), we set the cipher appropriately.
+	 * If the profile is set, we havent associated yet because our
+	 * cipher was incorrectly set. So we invalidate and send the
+	 * profile again.
+	 */
+	if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+	    key->cipher == WLAN_CIPHER_SUITE_WEP104) {
+		u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher;
+		u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher;
+
+		IWM_DBG_WEXT(iwm, DBG, "WEP key\n");
+
+		if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
+			*ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
+		if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
+			*ucast_cipher = *mcast_cipher =
+				UMAC_CIPHER_TYPE_WEP_104;
+
+		return iwm_reset_profile(iwm);
+	}
+
+	return iwm_set_key(iwm, 0, key);
+}
+
+static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+				u8 key_index, const u8 *mac_addr, void *cookie,
+				void (*callback)(void *cookie,
+						 struct key_params*))
+{
+	struct iwm_priv *iwm = ndev_to_iwm(ndev);
+	struct iwm_key *key = &iwm->keys[key_index];
+	struct key_params params;
+
+	IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
+
+	memset(&params, 0, sizeof(params));
+
+	params.cipher = key->cipher;
+	params.key_len = key->key_len;
+	params.seq_len = key->seq_len;
+	params.seq = key->seq;
+	params.key = key->key;
+
+	callback(cookie, &params);
+
+	return key->key_len ? 0 : -ENOENT;
+}
+
+
+static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+				u8 key_index, const u8 *mac_addr)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(ndev);
+	struct iwm_key *key = &iwm->keys[key_index];
+
+	if (!iwm->keys[key_index].key_len) {
+		IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
+		return 0;
+	}
+
+	if (key_index == iwm->default_key)
+		iwm->default_key = -1;
+
+	return iwm_set_key(iwm, 1, key);
+}
+
+static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
+					struct net_device *ndev,
+					u8 key_index)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(ndev);
+	int ret;
+
+	IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
+
+	if (!iwm->keys[key_index].key_len) {
+		IWM_ERR(iwm, "Key %d not used\n", key_index);
+		return -EINVAL;
+	}
+
+	ret = iwm_set_tx_key(iwm, key_index);
+	if (ret < 0)
+		return ret;
+
+	iwm->default_key = key_index;
+
+	return iwm_reset_profile(iwm);
+}
+
+
 int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
 {
 	struct wiphy *wiphy = iwm_to_wiphy(iwm);
@@ -331,6 +499,10 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 
 static struct cfg80211_ops iwm_cfg80211_ops = {
 	.change_virtual_intf = iwm_cfg80211_change_iface,
+	.add_key = iwm_cfg80211_add_key,
+	.get_key = iwm_cfg80211_get_key,
+	.del_key = iwm_cfg80211_del_key,
+	.set_default_key = iwm_cfg80211_set_default_key,
 	.scan = iwm_cfg80211_scan,
 	.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
 	.join_ibss = iwm_cfg80211_join_ibss,
drivers/net/wireless/iwmc3200wifi/commands.c +25 -47

170 lines not on this page · raw message

drivers/net/wireless/iwmc3200wifi/commands.h +1 -2
index 36b13a1..3510df8 100644
@@ -406,8 +406,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm);
 int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
 int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
 int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
-		struct iwm_key *key);
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
 int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
 int iwm_send_umac_channel_list(struct iwm_priv *iwm);
 int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
drivers/net/wireless/iwmc3200wifi/iwm.h +6 -8
index d8d4ae2..90b05d9 100644
@@ -162,13 +162,11 @@ struct iwm_umac_key_hdr {
 
 struct iwm_key {
 	struct iwm_umac_key_hdr hdr;
-	u8 in_use;
-	u8 alg;
-	u32 flags;
-	u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE];
-	u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE];
-	u8 key_len;
-	u8 key[32];
+	u32 cipher;
+	u8 key[WLAN_MAX_KEY_LEN];
+	u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
+	int key_len;
+	int seq_len;
 };
 
 #define IWM_RX_ID_HASH  0xff
@@ -276,7 +274,7 @@ struct iwm_priv {
 	struct iwm_tx_queue txq[IWM_TX_QUEUES];
 
 	struct iwm_key keys[IWM_NUM_KEYS];
-	struct iwm_key *default_key;
+	s8 default_key;
 
 	DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX);
 	wait_queue_head_t wifi_ntfy_queue;
drivers/net/wireless/iwmc3200wifi/main.c +2 -2
index 8448722..7f56c06 100644
@@ -230,7 +230,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
 	for (i = 0; i < IWM_NUM_KEYS; i++)
 		memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
 
-	iwm->default_key = NULL;
+	iwm->default_key = -1;
 
 	init_timer(&iwm->watchdog);
 	iwm->watchdog.function = iwm_watchdog;
@@ -709,7 +709,7 @@ int __iwm_down(struct iwm_priv *iwm)
 	iwm->umac_profile = NULL;
 	iwm_bss_list_clean(iwm);
 
-	iwm->default_key = NULL;
+	iwm->default_key = -1;
 	iwm->core_enabled = 0;
 
 	ret = iwm_bus_disable(iwm);
drivers/net/wireless/iwmc3200wifi/wext.c +13 -273

352 lines not on this page · raw message

Signature · 1 line
1.6.3.1
#8 lore raw

PATCH v2 8/11 iwmc3200wifi: change coexist periodic calibration flag

From: Zhu Yi <[email protected]>

The patch changes coexist periodic calibration priority flag. It also set wireless mode to UMAC and set PM control flag to 0x1.

---
 drivers/net/wireless/iwmc3200wifi/commands.c |   13 +++++++++----
 drivers/net/wireless/iwmc3200wifi/commands.h |    4 ++--
 2 files changed, 11 insertions(+), 6 deletions(-)
drivers/net/wireless/iwmc3200wifi/commands.c +9 -4
index 145f6f5..0d35afe 100644
@@ -120,7 +120,7 @@ static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
 	{4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
 	{3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
 	{5, 5, 0, COEX_CALIBRATION_FLAGS},
-	{4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
+	{3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
 	{5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS},
 	{4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
 	{4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
@@ -345,8 +345,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
 	return ret;
 }
 
-int iwm_send_umac_config(struct iwm_priv *iwm,
-			 __le32 reset_flags)
+int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
 {
 	int ret;
 
@@ -374,6 +373,12 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
 		return ret;
 
 	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_WIRELESS_MODE,
+				      iwm->conf.wireless_mode);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
 				      CFG_COEX_MODE, iwm->conf.coexist_mode);
 	if (ret < 0)
 		return ret;
@@ -415,7 +420,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
 		return ret;
 
 	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
-				      CFG_PM_CTRL_FLAGS, 0x30001);
+				      CFG_PM_CTRL_FLAGS, 0x1);
 	if (ret < 0)
 		return ret;
 
drivers/net/wireless/iwmc3200wifi/commands.h +2 -2
index 3510df8..e24d5b6 100644
@@ -106,8 +106,7 @@ enum {
 	CFG_TLC_SPATIAL_STREAM_SUPPORTED,
 	CFG_TLC_RETRY_PER_RATE,
 	CFG_TLC_RETRY_PER_HT_RATE,
-	CFG_TLC_FIXED_RATE,
-	CFG_TLC_FIXED_RATE_FLAGS,
+	CFG_TLC_FIXED_MCS,
 	CFG_TLC_CONTROL_FLAGS,
 	CFG_TLC_SR_MIN_FAIL,
 	CFG_TLC_SR_MIN_PASS,
@@ -232,6 +231,7 @@ struct iwm_umac_cmd_get_channel_list {
 /* Wireless mode */
 #define WIRELESS_MODE_11A  0x1
 #define WIRELESS_MODE_11G  0x2
+#define WIRELESS_MODE_11N  0x4
 
 #define UMAC_PROFILE_EX_IE_REQUIRED	0x1
 #define UMAC_PROFILE_QOS_ALLOWED	0x2
Signature · 1 line
1.6.3.1
#9 lore raw

PATCH v2 9/11 iwmc3200wifi: cache keys when interface is down

From: Samuel Ortiz <[email protected]>

When the interface is down and one sets a WEP key from userspace, we should be able to simply cache it.
Since that implies setting part of the profile's security settings, we now alloc/free the umac_profile at probe/remove time, and no longer at interface bring up/down time. Simply resetting it during the latter is enough.

---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |   12 ++++++++++--
 drivers/net/wireless/iwmc3200wifi/main.c     |   20 +++-----------------
 drivers/net/wireless/iwmc3200wifi/netdev.c   |   15 +++++++++++++++
 3 files changed, 28 insertions(+), 19 deletions(-)
drivers/net/wireless/iwmc3200wifi/cfg80211.c +10 -2
index ad62b20..71efbc1 100644
@@ -271,6 +271,10 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
 	if (key_index == iwm->default_key)
 		iwm->default_key = -1;
 
+	/* If the interface is down, we just cache this */
+	if (!test_bit(IWM_STATUS_READY, &iwm->status))
+		return 0;
+
 	return iwm_set_key(iwm, 1, key);
 }
 
@@ -288,12 +292,16 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
 		return -EINVAL;
 	}
 
+	iwm->default_key = key_index;
+
+	/* If the interface is down, we just cache this */
+	if (!test_bit(IWM_STATUS_READY, &iwm->status))
+		return 0;
+
 	ret = iwm_set_tx_key(iwm, key_index);
 	if (ret < 0)
 		return ret;
 
-	iwm->default_key = key_index;
-
 	return iwm_reset_profile(iwm);
 }
 
drivers/net/wireless/iwmc3200wifi/main.c +3 -17
index 7f56c06..930056b 100644
@@ -643,19 +643,10 @@ int __iwm_up(struct iwm_priv *iwm)
 		}
 	}
 
-	iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
-				    GFP_KERNEL);
-	if (!iwm->umac_profile) {
-		IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
-		goto err_fw;
-	}
-
-	iwm_init_default_profile(iwm, iwm->umac_profile);
-
 	ret = iwm_channels_init(iwm);
 	if (ret < 0) {
 		IWM_ERR(iwm, "Couldn't init channels\n");
-		goto err_profile;
+		goto err_fw;
 	}
 
 	/* Set the READY bit to indicate interface is brought up successfully */
@@ -663,10 +654,6 @@ int __iwm_up(struct iwm_priv *iwm)
 
 	return 0;
 
- err_profile:
-	kfree(iwm->umac_profile);
-	iwm->umac_profile = NULL;
-
  err_fw:
 	iwm_eeprom_exit(iwm);
 
@@ -705,10 +692,9 @@ int __iwm_down(struct iwm_priv *iwm)
 	clear_bit(IWM_STATUS_READY, &iwm->status);
 
 	iwm_eeprom_exit(iwm);
-	kfree(iwm->umac_profile);
-	iwm->umac_profile = NULL;
 	iwm_bss_list_clean(iwm);
-
+	iwm_init_default_profile(iwm, iwm->umac_profile);
+	iwm->umac_profile_active = false;
 	iwm->default_key = -1;
 	iwm->core_enabled = 0;
 
drivers/net/wireless/iwmc3200wifi/netdev.c +15 -0
index aaa20c6..d4deb4b 100644
@@ -48,6 +48,7 @@
 #include <linux/netdevice.h>
 
 #include "iwm.h"
+#include "commands.h"
 #include "cfg80211.h"
 #include "debug.h"
 
@@ -135,8 +136,20 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
 	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
 	wdev->netdev = ndev;
 
+	iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
+				    GFP_KERNEL);
+	if (!iwm->umac_profile) {
+		dev_err(dev, "Couldn't alloc memory for profile\n");
+		goto out_profile;
+	}
+
+	iwm_init_default_profile(iwm, iwm->umac_profile);
+
 	return iwm;
 
+ out_profile:
+	free_netdev(ndev);
+
  out_priv:
 	iwm_priv_deinit(iwm);
 
@@ -153,6 +166,8 @@ void iwm_if_free(struct iwm_priv *iwm)
 	free_netdev(iwm_to_ndev(iwm));
 	iwm_wdev_free(iwm);
 	iwm_priv_deinit(iwm);
+	kfree(iwm->umac_profile);
+	iwm->umac_profile = NULL;
 }
 
 int iwm_if_add(struct iwm_priv *iwm)
Signature · 1 line
1.6.3.1
#10 lore raw

PATCH v2 10/11 iwmc3200wifi: remove select LIB80211 from Kconfig

From: Zhu Yi <[email protected]>

iwmc3200wifi currently doesn't link with lib80211. So remove the Kconfig selection.

---
 drivers/net/wireless/iwmc3200wifi/Kconfig |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)
drivers/net/wireless/iwmc3200wifi/Kconfig +0 -1
index 651c0f6..1eccb6d 100644
@@ -3,7 +3,6 @@ config IWM
 	depends on MMC && WLAN_80211 && EXPERIMENTAL
 	depends on CFG80211
 	select WIRELESS_EXT
-	select LIB80211
 	select FW_LOADER
 
 config IWM_DEBUG
Signature · 1 line
1.6.3.1
#11 lore raw

PATCH v2 11/11 iwmc3200wifi: rfkill cleanup

From: Zhu Yi <[email protected]>

The patch cleans up the unused rfkill related structures and flags. It also adds wext and cfg80211 handlers for txpower auto and off so that software rfkill could be issued by user space.

---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |   24 ++++++++++++++++++++++++
 drivers/net/wireless/iwmc3200wifi/iwm.h      |    7 +------
 drivers/net/wireless/iwmc3200wifi/netdev.c   |   12 ++----------
 drivers/net/wireless/iwmc3200wifi/rx.c       |   18 +++++++++---------
 drivers/net/wireless/iwmc3200wifi/sdio.c     |    6 +-----
 drivers/net/wireless/iwmc3200wifi/wext.c     |    4 ++--
 6 files changed, 39 insertions(+), 32 deletions(-)
drivers/net/wireless/iwmc3200wifi/cfg80211.c +24 -0
index 71efbc1..e58026f 100644
@@ -505,6 +505,28 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 	return 0;
 }
 
+static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
+				    enum tx_power_setting type, int dbm)
+{
+	switch (type) {
+	case TX_POWER_AUTOMATIC:
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
+{
+	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+	*dbm = iwm->txpower;
+
+	return 0;
+}
+
 static struct cfg80211_ops iwm_cfg80211_ops = {
 	.change_virtual_intf = iwm_cfg80211_change_iface,
 	.add_key = iwm_cfg80211_add_key,
@@ -515,6 +537,8 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
 	.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
 	.join_ibss = iwm_cfg80211_join_ibss,
 	.leave_ibss = iwm_cfg80211_leave_ibss,
+	.set_tx_power = iwm_cfg80211_set_txpower,
+	.get_tx_power = iwm_cfg80211_get_txpower,
 };
 
 struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
drivers/net/wireless/iwmc3200wifi/iwm.h +1 -6
index 90b05d9..4da57f7 100644
@@ -184,10 +184,6 @@ struct iwm_key {
 #define IWM_STATUS_ASSOCIATING		3
 #define IWM_STATUS_ASSOCIATED		4
 
-#define IWM_RADIO_RFKILL_OFF		0
-#define IWM_RADIO_RFKILL_HW		1
-#define IWM_RADIO_RFKILL_SW		2
-
 struct iwm_tx_queue {
 	int id;
 	struct sk_buff_head queue;
@@ -221,7 +217,6 @@ struct iwm_priv {
 	struct iwm_conf conf;
 
 	unsigned long status;
-	unsigned long radio;
 
 	struct list_head pending_notif;
 	wait_queue_head_t notif_queue;
@@ -240,6 +235,7 @@ struct iwm_priv {
 	u8 bssid[ETH_ALEN];
 	u8 channel;
 	u16 rate;
+	u32 txpower;
 
 	struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM];
 	struct list_head bss_list;
@@ -290,7 +286,6 @@ struct iwm_priv {
 	struct timer_list watchdog;
 	struct work_struct reset_worker;
 	struct mutex mutex;
-	struct rfkill *rfkill;
 
 	char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 };
drivers/net/wireless/iwmc3200wifi/netdev.c +2 -10
index d4deb4b..e94e969 100644
@@ -55,23 +55,15 @@
 static int iwm_open(struct net_device *ndev)
 {
 	struct iwm_priv *iwm = ndev_to_iwm(ndev);
-	int ret = 0;
-
-	if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
-		ret = iwm_up(iwm);
 
-	return ret;
+	return iwm_up(iwm);
 }
 
 static int iwm_stop(struct net_device *ndev)
 {
 	struct iwm_priv *iwm = ndev_to_iwm(ndev);
-	int ret = 0;
-
-	if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
-		ret = iwm_down(iwm);
 
-	return ret;
+	return iwm_down(iwm);
 }
 
 /*
drivers/net/wireless/iwmc3200wifi/rx.c +9 -9
index 49a8be7..55871da 100644
@@ -143,17 +143,18 @@ static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf,
 				 unsigned long buf_size,
 				 struct iwm_wifi_cmd *cmd)
 {
+	struct wiphy *wiphy = iwm_to_wiphy(iwm);
 	struct iwm_umac_notif_init_complete *init_complete =
 			(struct iwm_umac_notif_init_complete *)(buf);
 	u16 status = le16_to_cpu(init_complete->status);
+	bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR);
 
-	if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) {
+	if (blocked)
 		IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n");
-		set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
-	} else {
+	else
 		IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n");
-		clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
-	}
+
+	wiphy_rfkill_set_hw_state(wiphy, blocked);
 
 	return 0;
 }
@@ -875,6 +876,7 @@ static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf,
 		/* UMAC passes rate info multiplies by 2 */
 		iwm->rate = max_rate >> 1;
 	}
+	iwm->txpower = le32_to_cpu(stats->tx_power);
 
 	wstats->status = 0;
 
@@ -1015,6 +1017,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
 static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
 			      unsigned long buf_size, struct iwm_wifi_cmd *cmd)
 {
+	struct wiphy *wiphy = iwm_to_wiphy(iwm);
 	struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *)
 				(buf + sizeof(struct iwm_umac_wifi_in_hdr));
 	u32 flags = le32_to_cpu(state->flags);
@@ -1023,10 +1026,7 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
 		 flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
 		 flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
 
-	if (flags & IWM_CARD_STATE_HW_DISABLED)
-		set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
-	else
-		clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
+	wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
 
 	return 0;
 }
drivers/net/wireless/iwmc3200wifi/sdio.c +1 -5
index 9166818..b93f620 100644
@@ -506,11 +506,7 @@ static struct sdio_driver iwm_sdio_driver = {
 
 static int __init iwm_sdio_init_module(void)
 {
-	int ret;
-
-	ret = sdio_register_driver(&iwm_sdio_driver);
-
-	return ret;
+	return sdio_register_driver(&iwm_sdio_driver);
 }
 
 static void __exit iwm_sdio_exit_module(void)
drivers/net/wireless/iwmc3200wifi/wext.c +2 -2
index 3062f37..9734573 100644
@@ -452,8 +452,8 @@ static const iw_handler iwm_handlers[] =
 	(iw_handler) cfg80211_wext_giwrts,		/* SIOCGIWRTS */
 	(iw_handler) cfg80211_wext_siwfrag,	        /* SIOCSIWFRAG */
 	(iw_handler) cfg80211_wext_giwfrag,		/* SIOCGIWFRAG */
-	(iw_handler) NULL,				/* SIOCSIWTXPOW */
-	(iw_handler) NULL,				/* SIOCGIWTXPOW */
+	(iw_handler) cfg80211_wext_siwtxpower,		/* SIOCSIWTXPOW */
+	(iw_handler) cfg80211_wext_giwtxpower,		/* SIOCGIWTXPOW */
 	(iw_handler) NULL,				/* SIOCSIWRETRY */
 	(iw_handler) NULL,				/* SIOCGIWRETRY */
 	(iw_handler) cfg80211_wext_siwencode,		/* SIOCSIWENCODE */
Signature · 1 line
1.6.3.1