* Re: iwlagn: possible regressions from 2.6.29 in 2.6.30
From: Paul Collins @ 2009-07-04 6:39 UTC (permalink / raw)
To: reinette chatre; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <87k52t9ynp.fsf@jenny.ondioline.org>
Paul Collins <paul@burly.ondioline.org> writes:
> reinette chatre <reinette.chatre@intel.com> writes:
>>> When I say "packets > 250 bytes" I mean 250-byte packets as claimed by
>>> "ping -s 222 mygateway":
>>>
>>> PING cornelius.lan (10.2.4.1) 222(250) bytes of data.
>>>
>>> The above will work, but "ping -s 223 cornelius" yields no replies.
>>
>> Are you saying this works before suspend, but not after resume? What do
>> you usually do to get this working again?
>
> Yes, normally it works great; I can ping with packet sizes up to the
> MTU. However, after suspend/resume and reassociation, "ping -s 223" or
> greater does not work. I get replies with "-s 222" or less,
> i.e. packets of 250 bytes or less.
>
> To get it working again I do "ifdown wlan0" followed by "ifup wlan0",
> which does the equivalent of "ip set link wlan0 down/up" and applying
> the network configuration.
>
> I will give the patch a shot when I get home.
I thought at first that the patch had moved the problem from reliably
reproducible to intermittently reproducible, but it looks like it was
simply intermittently reproducible the whole time. So, no change with
the patch applied.
--
Paul Collins
Wellington, New Zealand
Dag vijandelijk luchtschip de huismeester is dood
^ permalink raw reply
* Slow wired network when wireless card is also active
From: David Webber @ 2009-07-04 4:43 UTC (permalink / raw)
To: linux-wireless
I'm trying to use Jaunty on my Centrino laptop as a wireless access
point / NAT. My cable modem is plugged in to the ethernet port.
Strangely, when I enable the wireless card (via hostapd or simply
'ifconfig wlan1 192.168.0.1 up'), my WIRED network slows down. On a
terminal on the laptop, I see transfer speeds drop from over about 200
K/s to about 40 K/s. As far as I can tell, the problem is not affected
by iptables rules, ip_forward on/off, or ipv6. Just having the
wireless card present and active seems to affect the wired interface.
The problem may have something to do with having hostapd active, but
I'm not sure.
Aside: I have an intel wireless card built-in but since it can't do
hostap-mode, I purchased the ath9k cardbus card. The intel card is
disabled by function-key and is not active on boot. I have recent
versions of the kernel and hostapd from the subversion repositories
discussed on linuxwireless.org.
Linux version 2.6.30-custom-wl (root@whitebook) (gcc version 4.3.3
(Ubuntu 4.3.3-5ubuntu4) ) #1 SMP Thu Jun 18 19:22:02 CDT 2009
00:00.0 Host bridge: Intel Corporation 82852/82855 GM/GME/PM/GMV
Processor to I/O Controller (rev 02)
00:00.1 System peripheral: Intel Corporation 82852/82855 GM/GME/PM/GMV
Processor to I/O Controller (rev 02)
00:00.3 System peripheral: Intel Corporation 82852/82855 GM/GME/PM/GMV
Processor to I/O Controller (rev 02)
00:02.0 VGA compatible controller: Intel Corporation 82852/855GM
Integrated Graphics Device (rev 02)
00:02.1 Display controller: Intel Corporation 82852/855GM Integrated
Graphics Device (rev 02)
00:1d.0 USB Controller: Intel Corporation 82801DB/DBL/DBM
(ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 (rev 03)
00:1d.1 USB Controller: Intel Corporation 82801DB/DBL/DBM
(ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 (rev 03)
00:1d.2 USB Controller: Intel Corporation 82801DB/DBL/DBM
(ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 (rev 03)
00:1d.7 USB Controller: Intel Corporation 82801DB/DBM (ICH4/ICH4-M)
USB2 EHCI Controller (rev 03)
00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev 83)
00:1f.0 ISA bridge: Intel Corporation 82801DBM (ICH4-M) LPC Interface
Bridge (rev 03)
00:1f.1 IDE interface: Intel Corporation 82801DBM (ICH4-M) IDE
Controller (rev 03)
00:1f.3 SMBus: Intel Corporation 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M)
SMBus Controller (rev 03)
00:1f.5 Multimedia audio controller: Intel Corporation 82801DB/DBL/DBM
(ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller (rev 03)
00:1f.6 Modem: Intel Corporation 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M)
AC'97 Modem Controller (rev 03)
01:01.0 Network controller: Intel Corporation PRO/Wireless 2200BG
[Calexico2] Network Connection (rev 05)
01:02.0 Ethernet controller: Realtek Semiconductor Co., Ltd.
RTL-8139/8139C/8139C+ (rev 10)
01:04.0 CardBus bridge: Texas Instruments PCI1410 PC card Cardbus
Controller (rev 02)
01:05.0 FireWire (IEEE 1394): VIA Technologies, Inc. VT6306 Fire II
IEEE 1394 OHCI Link Layer Controller (rev 80)
02:00.0 Network controller: Atheros Communications Inc. AR5008
Wireless Network Adapter (rev 01)
Speed test:
(start with everything active. NAT works, other computers can reach
the internet through the laptop, but the speed is just slow. For this
test, no other machines were connected so they're not consuming the
bandwidth)
$ wget http://cosmos.cites.uiuc.edu/pub/ubuntu-iso/9.04/ubuntu-9.04-desktop-amd64.iso
[snip] 47.6K/s eta 4h 56m
$ sudo ifdown wlan1
[snip] 44.5K/s eta 5h 54m
$ sudo ifconfig mon.wlan1 down
[snip] 245K/s eta 45m 7s
As you can see, I lose about a factor of 5 when the wireless card is active.
I also posted this question to
https://answers.launchpad.net/ubuntu/+question/76037
Thanks in advance,
David
^ permalink raw reply
* 'skb_queue_is_last' and 'skb_queue_next' errors during make (2.6.31-rc1)
From: Brett Ussher @ 2009-07-04 2:44 UTC (permalink / raw)
To: linux-wireless
I keep getting an error when I try to make the 2.6.31-rc1 compat-wireless:
=====================================================================
compat-wireless-2.6.31-rc1 $ make
./scripts/gen-compat-autoconf.sh config.mk > include/linux/compat_autoconf.h
make -C /lib/modules/2.6.28-13-generic/build
M=/home/brett/Desktop/compat-wireless-2.6.31-rc1 modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.28-13-generic'
LD
/home/brett/Desktop/compat-wireless-2.6.31-rc1/drivers/misc/eeprom/built-in.o
CC [M]
/home/brett/Desktop/compat-wireless-2.6.31-rc1/drivers/misc/eeprom/eeprom_93cx6.o
In file included from <command-line>:0:
/home/brett/Desktop/compat-wireless-2.6.31-rc1/include/net/compat.h:123:
error: redefinition of ‘skb_queue_is_last’
include/linux/skbuff.h:477: error: previous definition of
‘skb_queue_is_last’ was here
/home/brett/Desktop/compat-wireless-2.6.31-rc1/include/net/compat.h:137:
error: redefinition of ‘skb_queue_next’
include/linux/skbuff.h:491: error: previous definition of
‘skb_queue_next’ was here
make[3]: ***
[/home/brett/Desktop/compat-wireless-2.6.31-rc1/drivers/misc/eeprom/eeprom_93cx6.o]
Error 1
make[2]: ***
[/home/brett/Desktop/compat-wireless-2.6.31-rc1/drivers/misc/eeprom] Error 2
make[1]: *** [_module_/home/brett/Desktop/compat-wireless-2.6.31-rc1]
Error 2
make[1]: Leaving directory `/usr/src/linux-headers-2.6.28-13-generic'
make: *** [modules] Error 2
=====================================================================
I'm using Ubuntu 9.04 with kernel 2.6.28-13-generic. Is there a way to
stop this error?
--
Brett D. Ussher
^ permalink raw reply
* Re: [WIP] p54: deal with allocation failures in rx path
From: Larry Finger @ 2009-07-04 2:16 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Max Filippov
In-Reply-To: <200907040053.05654.chunkeey@web.de>
Christian Lamparter wrote:
> This patch tries to address a long standing issue:
> how to survive serve memory starvation situations,
> without losing the device due to missing transfer-buffers.
>
> And with a flick of __GFP_NOWARN, we're able to handle ?all? memory
> allocation failures on the rx-side during operation without much fuss.
>
> However, there is still an issue within the xmit-part.
> This is likely due to p54's demand for a large free headroom for
> every outgoing frame:
>
-- snip --
> diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
> index 349375f..c9bc1da 100644
> --- a/drivers/net/wireless/p54/fwio.c
> +++ b/drivers/net/wireless/p54/fwio.c
> @@ -94,7 +94,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
> else
> priv->rx_mtu = (size_t)
> 0x620 - priv->tx_hdr_len;
> - maxlen = priv->tx_hdr_len + /* USB devices */
> + maxlen = priv->rx_hdr_len + /* USB devices */
> sizeof(struct p54_rx_data) +
> 4 + /* rx alignment */
> IEEE80211_MAX_FRAG_THRESHOLD;
> @@ -103,6 +103,18 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
> "to %d\n", priv->rx_mtu, maxlen);
> priv->rx_mtu = maxlen;
> }
> +
> + /*
> + * Firmware may insert up to 4 padding bytes after
> + * the lmac header, but it doesn't amend the size
> + * of data transfer.
> + * Such packets has correct data size in header, thus
===
s/has/have/
> + * referencing past the end of allocated skb.
> + * Therefore reserve 4 extra bytes for this case.
> + */
> + if (priv->rx_wa_extra_tail_space)
> + priv->rx_mtu += 4;
> +
> break;
> }
> case BR_CODE_EXPOSED_IF:
> @@ -312,7 +324,7 @@ int p54_setup_mac(struct p54_common *priv)
> {
> struct sk_buff *skb;
> struct p54_setup_mac *setup;
> - u16 mode;
> + u16 mode, rx_mtu = priv->rx_mtu;
>
> skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
> P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
> @@ -356,17 +368,25 @@ int p54_setup_mac(struct p54_common *priv)
> memcpy(setup->bssid, priv->bssid, ETH_ALEN);
> setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
> setup->rx_align = 0;
> +
> + /*
> + * reserve additional bytes to compensate for the possible
> + * alignment-caused truncation.
> + */
> + if (priv->rx_wa_extra_tail_space)
> + rx_mtu -= 4;
> +
> if (priv->fw_var < 0x500) {
> setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
> memset(setup->v1.rts_rates, 0, 8);
> setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
> - setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
> + setup->v1.max_rx = cpu_to_le16(rx_mtu);
> setup->v1.rxhw = cpu_to_le16(priv->rxhw);
> setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
> setup->v1.unalloc0 = cpu_to_le16(0);
> } else {
> setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
> - setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
> + setup->v2.max_rx = cpu_to_le16(rx_mtu);
> setup->v2.rxhw = cpu_to_le16(priv->rxhw);
> setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
> setup->v2.truncate = cpu_to_le16(48896);
> diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
> index 6772ed5..30ebde1 100644
> --- a/drivers/net/wireless/p54/p54.h
> +++ b/drivers/net/wireless/p54/p54.h
> @@ -176,6 +176,8 @@ struct p54_common {
>
> /* firmware/hardware info */
> unsigned int tx_hdr_len;
> + unsigned int rx_hdr_len;
> + bool rx_wa_extra_tail_space;
> unsigned int fw_var;
> unsigned int fw_interface;
> u8 version;
> @@ -234,7 +236,7 @@ struct p54_common {
> };
>
> /* interfaces for the drivers */
> -int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
> +struct sk_buff *p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
> void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
> int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
> int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
> @@ -245,5 +247,6 @@ int p54_register_common(struct ieee80211_hw *dev, struct device *pdev);
> void p54_free_common(struct ieee80211_hw *dev);
>
> void p54_unregister_common(struct ieee80211_hw *dev);
> +struct sk_buff *p54_alloc_rxskb(struct p54_common *priv, gfp_t gfp_mask);
>
> #endif /* P54_H */
> diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
> index d348c26..7d055da 100644
> --- a/drivers/net/wireless/p54/p54pci.c
> +++ b/drivers/net/wireless/p54/p54pci.c
> @@ -149,7 +149,7 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
> if (!desc->host_addr) {
> struct sk_buff *skb;
> dma_addr_t mapping;
> - skb = dev_alloc_skb(priv->common.rx_mtu + 32);
> + skb = dev_alloc_skb(priv->common.rx_mtu);
> if (!skb)
> break;
>
> @@ -186,6 +186,7 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
> (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);
> idx %= ring_limit;
> while (i != idx) {
> + dma_addr_t mapping;
> u16 len;
> struct sk_buff *skb;
> desc = &ring[i];
> @@ -197,25 +198,32 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
> i %= ring_limit;
> continue;
> }
> +
> + pci_unmap_single(priv->pdev,
> + le32_to_cpu(desc->host_addr),
> + priv->common.rx_mtu + 32,
> + PCI_DMA_FROMDEVICE);
> + rx_buf[i] = NULL;
> + desc->host_addr = 0;
> skb_put(skb, len);
>
> - if (p54_rx(dev, skb)) {
> - pci_unmap_single(priv->pdev,
> - le32_to_cpu(desc->host_addr),
> - priv->common.rx_mtu + 32,
> + skb = p54_rx(dev, skb);
> + mapping = pci_map_single(priv->pdev,
> + skb_tail_pointer(skb),
> + skb->len,
> PCI_DMA_FROMDEVICE);
> - rx_buf[i] = NULL;
> - desc->host_addr = 0;
> - } else {
> - skb_trim(skb, 0);
> - desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
> - }
> +
> + desc->host_addr = cpu_to_le32(mapping);
> + desc->device_addr = 0;
> + desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
> + desc->flags = 0;
> + rx_buf[i] = skb;
>
> i++;
> i %= ring_limit;
> }
> -
> - p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf);
> + wmb();
> + ring_control->host_idx[ring_index] = cpu_to_le32(idx);
> }
>
> /* caller must hold priv->lock */
> diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
> index 9b347ce..4c6ac3f 100644
> --- a/drivers/net/wireless/p54/p54spi.c
> +++ b/drivers/net/wireless/p54/p54spi.c
> @@ -389,14 +389,10 @@ static int p54spi_rx(struct p54s_priv *priv)
> return 0;
> }
>
> - /* Firmware may insert up to 4 padding bytes after the lmac header,
> - * but it does not amend the size of SPI data transfer.
> - * Such packets has correct data size in header, thus referencing
===
s/has/have/
> - * past the end of allocated skb. Reserve extra 4 bytes for this case */
> - skb = dev_alloc_skb(len + 4);
> + skb = skb_dequeue(&priv->rx_pool);
> if (!skb) {
> p54spi_sleep(priv);
> - dev_err(&priv->spi->dev, "could not alloc skb");
> + dev_err(&priv->spi->dev, "could not get skb");
> return -ENOMEM;
> }
>
> @@ -409,12 +405,9 @@ static int p54spi_rx(struct p54s_priv *priv)
> len - READAHEAD_SZ);
> }
> p54spi_sleep(priv);
> - /* Put additional bytes to compensate for the possible
> - * alignment-caused truncation */
> - skb_put(skb, 4);
>
> - if (p54_rx(priv->hw, skb) == 0)
> - dev_kfree_skb(skb);
> + skb = p54_rx(priv->hw, skb);
> + skb_queue_tail(&priv->rx_pool, skb);
>
> return 0;
> }
> @@ -629,6 +622,7 @@ static void p54spi_op_stop(struct ieee80211_hw *dev)
> static int __devinit p54spi_probe(struct spi_device *spi)
> {
> struct p54s_priv *priv = NULL;
> + struct sk_buff *skb;
> struct ieee80211_hw *hw;
> int ret = -EINVAL;
>
> @@ -645,6 +639,8 @@ static int __devinit p54spi_probe(struct spi_device *spi)
>
> spi->bits_per_word = 16;
> spi->max_speed_hz = 24000000;
> + skb_queue_head_init(&priv->rx_pool);
> + priv->common.rx_wa_extra_tail_space = true;
>
> ret = spi_setup(spi);
> if (ret < 0) {
> @@ -689,6 +685,11 @@ static int __devinit p54spi_probe(struct spi_device *spi)
> priv->common.stop = p54spi_op_stop;
> priv->common.tx = p54spi_op_tx;
>
> + skb = __dev_alloc_skb(priv->common.rx_mtu, GFP_KERNEL);
> + if (!skb)
> + goto err_free_common;
> + skb_queue_tail(&priv->rx_pool, skb);
> +
> ret = p54spi_request_firmware(hw);
> if (ret < 0)
> goto err_free_common;
> @@ -705,6 +706,7 @@ static int __devinit p54spi_probe(struct spi_device *spi)
>
> err_free_common:
> p54_free_common(priv->hw);
> + skb_queue_purge(&priv->rx_pool);
> return ret;
> }
>
> @@ -715,6 +717,7 @@ static int __devexit p54spi_remove(struct spi_device *spi)
> p54_unregister_common(priv->hw);
>
> free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
> + skb_queue_purge(&priv->rx_pool);
>
> gpio_free(p54spi_gpio_power);
> gpio_free(p54spi_gpio_irq);
> diff --git a/drivers/net/wireless/p54/p54spi.h b/drivers/net/wireless/p54/p54spi.h
> index 7fbe8d8..11ef2d5 100644
> --- a/drivers/net/wireless/p54/p54spi.h
> +++ b/drivers/net/wireless/p54/p54spi.h
> @@ -120,6 +120,8 @@ struct p54s_priv {
>
> enum fw_state fw_state;
> const struct firmware *firmware;
> +
> + struct sk_buff_head rx_pool;
> };
>
> #endif /* P54SPI_H */
> diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
> index 461d88f..c521bbc 100644
> --- a/drivers/net/wireless/p54/p54usb.c
> +++ b/drivers/net/wireless/p54/p54usb.c
> @@ -120,37 +120,14 @@ static void p54u_rx_cb(struct urb *urb)
> }
>
> skb_put(skb, urb->actual_length);
> + skb = p54_rx(dev, skb);
>
> - if (priv->hw_type == P54U_NET2280)
> - skb_pull(skb, priv->common.tx_hdr_len);
> - if (priv->common.fw_interface == FW_LM87) {
> - skb_pull(skb, 4);
> - skb_put(skb, 4);
> - }
> -
> - if (p54_rx(dev, skb)) {
> - skb = dev_alloc_skb(priv->common.rx_mtu + 32);
> - if (unlikely(!skb)) {
> - /* TODO check rx queue length and refill *somewhere* */
> - return;
> - }
> + info = (struct p54u_rx_info *) skb->cb;
> + info->urb = urb;
> + info->dev = dev;
> + urb->transfer_buffer = skb_tail_pointer(skb);
> + urb->context = skb;
>
> - info = (struct p54u_rx_info *) skb->cb;
> - info->urb = urb;
> - info->dev = dev;
> - urb->transfer_buffer = skb_tail_pointer(skb);
> - urb->context = skb;
> - } else {
> - if (priv->hw_type == P54U_NET2280)
> - skb_push(skb, priv->common.tx_hdr_len);
> - if (priv->common.fw_interface == FW_LM87) {
> - skb_push(skb, 4);
> - skb_put(skb, 4);
> - }
> - skb_reset_tail_pointer(skb);
> - skb_trim(skb, 0);
> - urb->transfer_buffer = skb_tail_pointer(skb);
> - }
> skb_queue_tail(&priv->rx_queue, skb);
> usb_anchor_urb(urb, &priv->submitted);
> if (usb_submit_urb(urb, GFP_ATOMIC)) {
> @@ -186,7 +163,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
> int ret = 0;
>
> while (skb_queue_len(&priv->rx_queue) < 32) {
> - skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
> + skb = __dev_alloc_skb(priv->common.rx_mtu, GFP_KERNEL);
> if (!skb) {
> ret = -ENOMEM;
> goto err;
> @@ -927,14 +904,17 @@ static int __devinit p54u_probe(struct usb_interface *intf,
> #endif
>
> priv->hw_type = P54U_3887;
> + priv->common.rx_wa_extra_tail_space = true;
> dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
> priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
> + priv->common.rx_hdr_len = sizeof(struct lm87_rx_hdr);
> priv->common.tx = p54u_tx_lm87;
> priv->upload_fw = p54u_upload_firmware_3887;
> } else {
> priv->hw_type = P54U_NET2280;
> dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
> priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
> + priv->common.rx_hdr_len = sizeof(struct net2280_tx_hdr);
==
Should this be rx rather than tx?
-- skip --
I have a problem that is not new with this patch. Using p54usb with
LM87 firmware and under the heavy load of building a kernel with the
source tree mounted with NFS, the interface will go off-line and
cannot reconnect. When the driver is unloaded and reloaded, it is
unable to reload the firmware. My log is as follows:
usb 1-5: new high speed USB device using ehci_hcd and address 3
usb 1-5: configuration #1 chosen from 1 choice
cfg80211: Calling CRDA to update world regulatory domain
usb 1-5: reset high speed USB device using ehci_hcd and address 3
usb 1-5: firmware: requesting isl3887usb
phy0: p54 detected a LM87 firmware
p54: rx_mtu reduced from 3240 to 2380
phy0: FW rev 2.13.24.0 - Softmac protocol 5.9
phy0: cryptographic accelerator WEP:YES, TKIP:YES, CCMP:YES
phy0: hwaddr 00:90:4b:d2:1f:cd, MAC:isl3892 RF:Xbow
phy0: Selected rate control algorithm 'minstrel'
Registered led device: p54-phy0::assoc
Registered led device: p54-phy0::tx
Registered led device: p54-phy0::rx
Registered led device: p54-phy0::radio
usb 1-5: is registered as 'phy0'
usbcore: registered new interface driver p54usb
wlan0: authenticate with AP 00:1a:70:46:ba:b1
wlan0: authenticated
wlan0: associate with AP 00:1a:70:46:ba:b1
wlan0: RX AssocResp from 00:1a:70:46:ba:b1 (capab=0x431 status=0 aid=1)
wlan0: associated
wlan0: no probe response from AP 00:1a:70:46:ba:b1 - disassociating
usbcore: deregistering interface driver p54usb
cfg80211: Calling CRDA to update world regulatory domain
usb 1-5: reset high speed USB device using ehci_hcd and address 3
usb 1-5: firmware: requesting isl3887usb
phy0: p54 detected a LM87 firmware
p54: rx_mtu reduced from 3240 to 2380
phy0: FW rev 2.13.24.0 - Softmac protocol 5.9
phy0: cryptographic accelerator WEP:YES, TKIP:YES, CCMP:YES
usb 1-5: (p54usb) firmware upload failed!
p54usb: probe of 1-5:1.0 failed with error -110
^ permalink raw reply
* Re: [WIP] p54: deal with allocation failures in rx path
From: Larry Finger @ 2009-07-04 1:09 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Max Filippov
In-Reply-To: <200907040053.05654.chunkeey@web.de>
Christian Lamparter wrote:
> This patch tries to address a long standing issue:
> how to survive serve memory starvation situations,
> without losing the device due to missing transfer-buffers.
>
> And with a flick of __GFP_NOWARN, we're able to handle ?all? memory
> allocation failures on the rx-side during operation without much fuss.
>
> However, there is still an issue within the xmit-part.
> This is likely due to p54's demand for a large free headroom for
> every outgoing frame:
>
> + transport header (differs from device to device)
> -> 16 bytes transport header (USB 1st gen)
> -> 8 bytes for (USB 2nd gen)
> -> 0 bytes for spi & pci
> + 12 bytes for p54_hdr
> + 44 bytes for p54_tx_data
> + up to 3 bytes for alignment
> (+ 802.11 header as well? )
>
> and this is where ieee80211_skb_resize comes into the play...
> which will try to _relocate_ (alloc new, copy, free old) frame data,
> as the headroom is most of the time simply not enough.
> =>
> Call Trace: (from Larry - Bug #13319 )
> [<ffffffff80292a7b>] __alloc_pages_internal+0x43d/0x45e
> [<ffffffff802b1f1f>] alloc_pages_current+0xbe/0xc6
> [<ffffffff802b6362>] new_slab+0xcf/0x28b
> [<ffffffff802b4d1f>] ? unfreeze_slab+0x4c/0xbd
> [<ffffffff802b672e>] __slab_alloc+0x210/0x44c
> [<ffffffff803e7bee>] ? pskb_expand_head+0x52/0x166
> [<ffffffff803e7bee>] ? pskb_expand_head+0x52/0x166
> [<ffffffff802b7e60>] __kmalloc+0x119/0x194
> [<ffffffff803e7bee>] pskb_expand_head+0x52/0x166
> [<ffffffffa02913d6>] ieee80211_skb_resize+0x91/0xc7 [mac80211]
> [<ffffffffa0291c0f>] ieee80211_master_start_xmit+0x298/0x319 [mac80211]
> [<ffffffff803ef72a>] dev_hard_start_xmit+0x229/0x2a8
> (sl*b debug option will help to bloat even more.)
>
> So?! how to prevent ieee80211_skb_resize from raping
> the bits of memory left?
>
> the simplest answer is probably this one:
> https://dev.openwrt.org/changeset/15761
Christian,
I have not had a change to review and/or test this patch. I applaud
attempts to reduce memory, but the problem that I reported will be
fixed in 2.6.31. Whenever the SLUB debugging would force the order of
the request to increase, debugging will be turned off for that request
and a notification will be logged. This solution represents a
compromise among the developers - as usual none of them are really
happy with this approach, and it is expected that there will be
further development for 2.6.32.
After I test this patch, I will try reverting the change that reduced
MTU on the chance that it will no longer be necessary.
Larry
^ permalink raw reply
* Re: Memory leak in iwlwifi or false positive?
From: Catalin Marinas @ 2009-07-03 23:17 UTC (permalink / raw)
To: reinette chatre; +Cc: linux-wireless@vger.kernel.org, linux-kernel
In-Reply-To: <1246573533.17896.867.camel@rc-desk>
Hi Reinette,
On Thu, 2009-07-02 at 15:25 -0700, reinette chatre wrote:
> On Thu, 2009-07-02 at 14:32 -0700, Catalin Marinas wrote:
> > pushed yet) it seems to no longer show so many random leaks. However, I
> > get a lot of leaks reported in the iwlwifi code, about 4800 and they do
> > not disappear from any subsequent memory scanning (as is usually the
> > case with false positives). There are a lot of kmalloc's of < 512 bytes
> > and /proc/slabinfo seems to be in line with this:
[...]
> Yes - this sounds about right. You tested with 5100 hardware which by
> default initializes 20 TX queues. For each of these queues it maintains
> a 256 buffer array of commands with 356 bytes used for each command.
With the latest kmemleak changes which I pushed to Linus they
disappeared. I missed the kmalloc_large in slub and probably some of the
root objects that keep references to others weren't scanned (maybe the
kzalloc call in wiphy_new was missed as it links to all the bulk of the
reported objects in the iwlwifi code).
Thanks.
--
Catalin
^ permalink raw reply
* [WIP] p54: deal with allocation failures in rx path
From: Christian Lamparter @ 2009-07-03 22:53 UTC (permalink / raw)
To: linux-wireless; +Cc: Larry Finger, Max Filippov
This patch tries to address a long standing issue:
how to survive serve memory starvation situations,
without losing the device due to missing transfer-buffers.
And with a flick of __GFP_NOWARN, we're able to handle ?all? memory
allocation failures on the rx-side during operation without much fuss.
However, there is still an issue within the xmit-part.
This is likely due to p54's demand for a large free headroom for
every outgoing frame:
+ transport header (differs from device to device)
-> 16 bytes transport header (USB 1st gen)
-> 8 bytes for (USB 2nd gen)
-> 0 bytes for spi & pci
+ 12 bytes for p54_hdr
+ 44 bytes for p54_tx_data
+ up to 3 bytes for alignment
(+ 802.11 header as well? )
and this is where ieee80211_skb_resize comes into the play...
which will try to _relocate_ (alloc new, copy, free old) frame data,
as the headroom is most of the time simply not enough.
=>
Call Trace: (from Larry - Bug #13319 )
[<ffffffff80292a7b>] __alloc_pages_internal+0x43d/0x45e
[<ffffffff802b1f1f>] alloc_pages_current+0xbe/0xc6
[<ffffffff802b6362>] new_slab+0xcf/0x28b
[<ffffffff802b4d1f>] ? unfreeze_slab+0x4c/0xbd
[<ffffffff802b672e>] __slab_alloc+0x210/0x44c
[<ffffffff803e7bee>] ? pskb_expand_head+0x52/0x166
[<ffffffff803e7bee>] ? pskb_expand_head+0x52/0x166
[<ffffffff802b7e60>] __kmalloc+0x119/0x194
[<ffffffff803e7bee>] pskb_expand_head+0x52/0x166
[<ffffffffa02913d6>] ieee80211_skb_resize+0x91/0xc7 [mac80211]
[<ffffffffa0291c0f>] ieee80211_master_start_xmit+0x298/0x319 [mac80211]
[<ffffffff803ef72a>] dev_hard_start_xmit+0x229/0x2a8
(sl*b debug option will help to bloat even more.)
So?! how to prevent ieee80211_skb_resize from raping
the bits of memory left?
the simplest answer is probably this one:
https://dev.openwrt.org/changeset/15761
--
back to rx failures.
the attached code below was only usb was tested so far!
you have been warned!
regards,
chr
btw: max what do you think about the p54spi changes, are they total ****?
---
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 349375f..c9bc1da 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -94,7 +94,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
else
priv->rx_mtu = (size_t)
0x620 - priv->tx_hdr_len;
- maxlen = priv->tx_hdr_len + /* USB devices */
+ maxlen = priv->rx_hdr_len + /* USB devices */
sizeof(struct p54_rx_data) +
4 + /* rx alignment */
IEEE80211_MAX_FRAG_THRESHOLD;
@@ -103,6 +103,18 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
"to %d\n", priv->rx_mtu, maxlen);
priv->rx_mtu = maxlen;
}
+
+ /*
+ * Firmware may insert up to 4 padding bytes after
+ * the lmac header, but it doesn't amend the size
+ * of data transfer.
+ * Such packets has correct data size in header, thus
+ * referencing past the end of allocated skb.
+ * Therefore reserve 4 extra bytes for this case.
+ */
+ if (priv->rx_wa_extra_tail_space)
+ priv->rx_mtu += 4;
+
break;
}
case BR_CODE_EXPOSED_IF:
@@ -312,7 +324,7 @@ int p54_setup_mac(struct p54_common *priv)
{
struct sk_buff *skb;
struct p54_setup_mac *setup;
- u16 mode;
+ u16 mode, rx_mtu = priv->rx_mtu;
skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
@@ -356,17 +368,25 @@ int p54_setup_mac(struct p54_common *priv)
memcpy(setup->bssid, priv->bssid, ETH_ALEN);
setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
setup->rx_align = 0;
+
+ /*
+ * reserve additional bytes to compensate for the possible
+ * alignment-caused truncation.
+ */
+ if (priv->rx_wa_extra_tail_space)
+ rx_mtu -= 4;
+
if (priv->fw_var < 0x500) {
setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
memset(setup->v1.rts_rates, 0, 8);
setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
- setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v1.max_rx = cpu_to_le16(rx_mtu);
setup->v1.rxhw = cpu_to_le16(priv->rxhw);
setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
setup->v1.unalloc0 = cpu_to_le16(0);
} else {
setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
- setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v2.max_rx = cpu_to_le16(rx_mtu);
setup->v2.rxhw = cpu_to_le16(priv->rxhw);
setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
setup->v2.truncate = cpu_to_le16(48896);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 6772ed5..30ebde1 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -176,6 +176,8 @@ struct p54_common {
/* firmware/hardware info */
unsigned int tx_hdr_len;
+ unsigned int rx_hdr_len;
+ bool rx_wa_extra_tail_space;
unsigned int fw_var;
unsigned int fw_interface;
u8 version;
@@ -234,7 +236,7 @@ struct p54_common {
};
/* interfaces for the drivers */
-int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
+struct sk_buff *p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
@@ -245,5 +247,6 @@ int p54_register_common(struct ieee80211_hw *dev, struct device *pdev);
void p54_free_common(struct ieee80211_hw *dev);
void p54_unregister_common(struct ieee80211_hw *dev);
+struct sk_buff *p54_alloc_rxskb(struct p54_common *priv, gfp_t gfp_mask);
#endif /* P54_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index d348c26..7d055da 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -149,7 +149,7 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
if (!desc->host_addr) {
struct sk_buff *skb;
dma_addr_t mapping;
- skb = dev_alloc_skb(priv->common.rx_mtu + 32);
+ skb = dev_alloc_skb(priv->common.rx_mtu);
if (!skb)
break;
@@ -186,6 +186,7 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
(*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);
idx %= ring_limit;
while (i != idx) {
+ dma_addr_t mapping;
u16 len;
struct sk_buff *skb;
desc = &ring[i];
@@ -197,25 +198,32 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
i %= ring_limit;
continue;
}
+
+ pci_unmap_single(priv->pdev,
+ le32_to_cpu(desc->host_addr),
+ priv->common.rx_mtu + 32,
+ PCI_DMA_FROMDEVICE);
+ rx_buf[i] = NULL;
+ desc->host_addr = 0;
skb_put(skb, len);
- if (p54_rx(dev, skb)) {
- pci_unmap_single(priv->pdev,
- le32_to_cpu(desc->host_addr),
- priv->common.rx_mtu + 32,
+ skb = p54_rx(dev, skb);
+ mapping = pci_map_single(priv->pdev,
+ skb_tail_pointer(skb),
+ skb->len,
PCI_DMA_FROMDEVICE);
- rx_buf[i] = NULL;
- desc->host_addr = 0;
- } else {
- skb_trim(skb, 0);
- desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
- }
+
+ desc->host_addr = cpu_to_le32(mapping);
+ desc->device_addr = 0;
+ desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
+ desc->flags = 0;
+ rx_buf[i] = skb;
i++;
i %= ring_limit;
}
-
- p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf);
+ wmb();
+ ring_control->host_idx[ring_index] = cpu_to_le32(idx);
}
/* caller must hold priv->lock */
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 9b347ce..4c6ac3f 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -389,14 +389,10 @@ static int p54spi_rx(struct p54s_priv *priv)
return 0;
}
- /* Firmware may insert up to 4 padding bytes after the lmac header,
- * but it does not amend the size of SPI data transfer.
- * Such packets has correct data size in header, thus referencing
- * past the end of allocated skb. Reserve extra 4 bytes for this case */
- skb = dev_alloc_skb(len + 4);
+ skb = skb_dequeue(&priv->rx_pool);
if (!skb) {
p54spi_sleep(priv);
- dev_err(&priv->spi->dev, "could not alloc skb");
+ dev_err(&priv->spi->dev, "could not get skb");
return -ENOMEM;
}
@@ -409,12 +405,9 @@ static int p54spi_rx(struct p54s_priv *priv)
len - READAHEAD_SZ);
}
p54spi_sleep(priv);
- /* Put additional bytes to compensate for the possible
- * alignment-caused truncation */
- skb_put(skb, 4);
- if (p54_rx(priv->hw, skb) == 0)
- dev_kfree_skb(skb);
+ skb = p54_rx(priv->hw, skb);
+ skb_queue_tail(&priv->rx_pool, skb);
return 0;
}
@@ -629,6 +622,7 @@ static void p54spi_op_stop(struct ieee80211_hw *dev)
static int __devinit p54spi_probe(struct spi_device *spi)
{
struct p54s_priv *priv = NULL;
+ struct sk_buff *skb;
struct ieee80211_hw *hw;
int ret = -EINVAL;
@@ -645,6 +639,8 @@ static int __devinit p54spi_probe(struct spi_device *spi)
spi->bits_per_word = 16;
spi->max_speed_hz = 24000000;
+ skb_queue_head_init(&priv->rx_pool);
+ priv->common.rx_wa_extra_tail_space = true;
ret = spi_setup(spi);
if (ret < 0) {
@@ -689,6 +685,11 @@ static int __devinit p54spi_probe(struct spi_device *spi)
priv->common.stop = p54spi_op_stop;
priv->common.tx = p54spi_op_tx;
+ skb = __dev_alloc_skb(priv->common.rx_mtu, GFP_KERNEL);
+ if (!skb)
+ goto err_free_common;
+ skb_queue_tail(&priv->rx_pool, skb);
+
ret = p54spi_request_firmware(hw);
if (ret < 0)
goto err_free_common;
@@ -705,6 +706,7 @@ static int __devinit p54spi_probe(struct spi_device *spi)
err_free_common:
p54_free_common(priv->hw);
+ skb_queue_purge(&priv->rx_pool);
return ret;
}
@@ -715,6 +717,7 @@ static int __devexit p54spi_remove(struct spi_device *spi)
p54_unregister_common(priv->hw);
free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
+ skb_queue_purge(&priv->rx_pool);
gpio_free(p54spi_gpio_power);
gpio_free(p54spi_gpio_irq);
diff --git a/drivers/net/wireless/p54/p54spi.h b/drivers/net/wireless/p54/p54spi.h
index 7fbe8d8..11ef2d5 100644
--- a/drivers/net/wireless/p54/p54spi.h
+++ b/drivers/net/wireless/p54/p54spi.h
@@ -120,6 +120,8 @@ struct p54s_priv {
enum fw_state fw_state;
const struct firmware *firmware;
+
+ struct sk_buff_head rx_pool;
};
#endif /* P54SPI_H */
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 461d88f..c521bbc 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -120,37 +120,14 @@ static void p54u_rx_cb(struct urb *urb)
}
skb_put(skb, urb->actual_length);
+ skb = p54_rx(dev, skb);
- if (priv->hw_type == P54U_NET2280)
- skb_pull(skb, priv->common.tx_hdr_len);
- if (priv->common.fw_interface == FW_LM87) {
- skb_pull(skb, 4);
- skb_put(skb, 4);
- }
-
- if (p54_rx(dev, skb)) {
- skb = dev_alloc_skb(priv->common.rx_mtu + 32);
- if (unlikely(!skb)) {
- /* TODO check rx queue length and refill *somewhere* */
- return;
- }
+ info = (struct p54u_rx_info *) skb->cb;
+ info->urb = urb;
+ info->dev = dev;
+ urb->transfer_buffer = skb_tail_pointer(skb);
+ urb->context = skb;
- info = (struct p54u_rx_info *) skb->cb;
- info->urb = urb;
- info->dev = dev;
- urb->transfer_buffer = skb_tail_pointer(skb);
- urb->context = skb;
- } else {
- if (priv->hw_type == P54U_NET2280)
- skb_push(skb, priv->common.tx_hdr_len);
- if (priv->common.fw_interface == FW_LM87) {
- skb_push(skb, 4);
- skb_put(skb, 4);
- }
- skb_reset_tail_pointer(skb);
- skb_trim(skb, 0);
- urb->transfer_buffer = skb_tail_pointer(skb);
- }
skb_queue_tail(&priv->rx_queue, skb);
usb_anchor_urb(urb, &priv->submitted);
if (usb_submit_urb(urb, GFP_ATOMIC)) {
@@ -186,7 +163,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
int ret = 0;
while (skb_queue_len(&priv->rx_queue) < 32) {
- skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
+ skb = __dev_alloc_skb(priv->common.rx_mtu, GFP_KERNEL);
if (!skb) {
ret = -ENOMEM;
goto err;
@@ -927,14 +904,17 @@ static int __devinit p54u_probe(struct usb_interface *intf,
#endif
priv->hw_type = P54U_3887;
+ priv->common.rx_wa_extra_tail_space = true;
dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
+ priv->common.rx_hdr_len = sizeof(struct lm87_rx_hdr);
priv->common.tx = p54u_tx_lm87;
priv->upload_fw = p54u_upload_firmware_3887;
} else {
priv->hw_type = P54U_NET2280;
dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
+ priv->common.rx_hdr_len = sizeof(struct net2280_tx_hdr);
priv->common.tx = p54u_tx_net2280;
priv->upload_fw = p54u_upload_firmware_net2280;
}
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
index e935b79..685a2b4 100644
--- a/drivers/net/wireless/p54/p54usb.h
+++ b/drivers/net/wireless/p54/p54usb.h
@@ -77,6 +77,10 @@ struct lm87_tx_hdr {
__le32 chksum;
} __attribute__((packed));
+struct lm87_rx_hdr {
+ __le32 chksum;
+} __packed;
+
/* Some flags for the isl hardware registers controlling DMA inside the
* chip */
#define ISL38XX_DMA_STATUS_DONE 0x00000001
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index ea074a6..45e5e88 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -324,10 +324,11 @@ static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
}
}
-static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
+static struct sk_buff *p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
{
struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+ struct sk_buff *tmp;
u16 freq = le16_to_cpu(hdr->freq);
size_t header_len = sizeof(*hdr);
u32 tsf32;
@@ -339,10 +340,14 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
* nasty crash.
*/
if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return 0;
+ return skb;
if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD)))
- return 0;
+ return skb;
+
+ tmp = dev_alloc_skb(priv->rx_mtu);
+ if (!tmp)
+ return skb;
if (hdr->decrypt_status == P54_DECRYPT_OK)
rx_status->flag |= RX_FLAG_DECRYPTED;
@@ -384,7 +389,7 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
queue_delayed_work(priv->hw->workqueue, &priv->work,
msecs_to_jiffies(P54_STATISTICS_UPDATE));
- return -1;
+ return tmp;
}
static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
@@ -566,7 +571,7 @@ static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
}
}
-static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
+static struct sk_buff *p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
{
struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
@@ -590,19 +595,52 @@ static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
wiphy_name(priv->hw->wiphy), le16_to_cpu(hdr->type));
break;
}
- return 0;
+ return skb;
}
-/* returns zero if skb can be reused */
-int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
+/* returns a new skb in case the old one was send to mac80211. */
+struct sk_buff *p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54_common *priv = dev->priv;
- u16 type = le16_to_cpu(*((__le16 *)skb->data));
+ struct sk_buff *replacement;
+ struct p54_hdr *hdr;
+
+ if (unlikely(skb->len < sizeof(*hdr) + priv->rx_hdr_len)) {
+ if (net_ratelimit())
+ printk(KERN_ERR "%s: short read! - if this message "
+ "persists => check the device or cable.\n",
+ wiphy_name(dev->wiphy));
+
+ return skb;
+ }
+
+ if (priv->rx_wa_extra_tail_space) {
+ /*
+ * Put additional bytes to compensate for the possible
+ * alignment-caused truncation.
+ */
+
+ skb_put(skb, 4);
+ }
+
+ skb_pull(skb, priv->rx_hdr_len);
+ hdr = (void *) skb->data;
- if (type & P54_HDR_FLAG_CONTROL)
- return p54_rx_control(priv, skb);
+ if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_CONTROL))
+ replacement = p54_rx_control(priv, skb);
else
- return p54_rx_data(priv, skb);
+ replacement = p54_rx_data(priv, skb);
+
+ if (replacement == skb) {
+ /*
+ * This skb was not _consumed_ by mac80211.
+ * Reinitialize dirty data structure before returning it back.
+ */
+
+ skb_put(skb, priv->rx_hdr_len);
+ skb_trim(skb, 0);
+ }
+ return replacement;
}
EXPORT_SYMBOL_GPL(p54_rx);
^ permalink raw reply related
* [PATCH] p54: two endian fixes
From: Christian Lamparter @ 2009-07-03 19:01 UTC (permalink / raw)
To: linux-wireless; +Cc: John W. Linville, Max Filippov
This patch fixes all CHECK_ENDIAN complains:
1. p54/fwio.c:296:6: warning: restricted __le32 degrades to integer
p54/fwio.c:296:6: warning: restricted __le32 degrades to integer
2. p54/p54spi.c:172:32: warning: incorrect type in initializer
p54spi.c:172:32: expected restricted __le32 [usertype] buffer
p54/p54spi.c:172:32: got unsigned int
Signed-off-by: Christian Lamparter <chunkeey@web.de>
---
Max,
drivers/net/wireless/p54/p54spi.c:115: warning: ‘p54spi_read16’ defined but not used
looks like this function can be nuked, or do you have plans with it?
---
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 9bff43d..349375f 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -292,8 +292,9 @@ int p54_tx_cancel(struct p54_common *priv, __le32 req_id)
{
struct sk_buff *skb;
struct p54_txcancel *cancel;
+ u32 _req_id = le32_to_cpu(req_id);
- if (unlikely(req_id < priv->rx_start || req_id > priv->rx_end))
+ if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end))
return -EINVAL;
skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 7ef191a..9b347ce 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -164,12 +164,12 @@ static const struct p54spi_spi_reg p54spi_registers_array[] =
{ SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_RD_BASE " }
};
-static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
+static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits)
{
int i;
for (i = 0; i < 2000; i++) {
- __le32 buffer = p54spi_read32(priv, reg);
+ u32 buffer = p54spi_read32(priv, reg);
if ((buffer & bits) == bits)
return 1;
}
@@ -179,8 +179,7 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base,
const void *buf, size_t len)
{
- if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL,
- cpu_to_le32(HOST_ALLOWED))) {
+ if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, HOST_ALLOWED)) {
dev_err(&priv->spi->dev, "spi_write_dma not allowed "
"to DMA write.\n");
return -EAGAIN;
@@ -333,7 +332,7 @@ static int p54spi_wakeup(struct p54s_priv *priv)
/* And wait for the READY interrupt */
if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
- cpu_to_le32(SPI_HOST_INT_READY))) {
+ SPI_HOST_INT_READY)) {
dev_err(&priv->spi->dev, "INT_READY timeout\n");
return -EBUSY;
}
@@ -444,7 +443,7 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb)
goto out;
if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
- cpu_to_le32(SPI_HOST_INT_WR_READY))) {
+ SPI_HOST_INT_WR_READY)) {
dev_err(&priv->spi->dev, "WR_READY timeout\n");
ret = -EAGAIN;
goto out;
^ permalink raw reply related
* Re: [PATCH] iwmc3200wifi: cfg80211 managed mode port
From: Samuel Ortiz @ 2009-07-03 13:10 UTC (permalink / raw)
To: Johannes Berg; +Cc: Zhu, Yi, John Linville, linux-wireless@vger.kernel.org
In-Reply-To: <1246608159.16770.53.camel@johannes.local>
On Fri, Jul 03, 2009 at 01:02:39AM -0700, Johannes Berg wrote:
> On Fri, 2009-07-03 at 01:55 +0200, Samuel Ortiz wrote:
> > This patch ports iwm to the new cfg80211 managed mode API.
> > Whenever those managed mode routines get combined with the ibss one, we will
> > just have to entirely get rid of the wext implementation (We may have to only
> > keep the iw_handler until cfg80211 does the wext registration for us).
>
> Looks good. I'll take care of the combine part later.
Thanks in advance.
Cheers,
Samuel.
> johannes
>
> > Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
> > ---
> > drivers/net/wireless/iwmc3200wifi/cfg80211.c | 195 ++++++++++++++++
> > drivers/net/wireless/iwmc3200wifi/rx.c | 13 -
> > drivers/net/wireless/iwmc3200wifi/wext.c | 320 ++-------------------------
> > 3 files changed, 239 insertions(+), 289 deletions(-)
> >
> > Index: iwm-2.6/drivers/net/wireless/iwmc3200wifi/cfg80211.c
> > ===================================================================
> > --- iwm-2.6.orig/drivers/net/wireless/iwmc3200wifi/cfg80211.c 2009-07-02 21:20:34.000000000 +0200
> > +++ iwm-2.6/drivers/net/wireless/iwmc3200wifi/cfg80211.c 2009-07-03 01:43:09.000000000 +0200
> > @@ -305,6 +305,25 @@ static int iwm_cfg80211_set_default_key(
> > return iwm_reset_profile(iwm);
> > }
> >
> > +int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
> > + u8 *mac, struct station_info *sinfo)
> > +{
> > + struct iwm_priv *iwm = ndev_to_iwm(ndev);
> > +
> > + if (memcmp(mac, iwm->bssid, ETH_ALEN))
> > + return -ENOENT;
> > +
> > + sinfo->filled |= STATION_INFO_TX_BITRATE;
> > + sinfo->txrate.legacy = iwm->rate * 10;
> > +
> > + if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
> > + sinfo->filled |= STATION_INFO_SIGNAL;
> > + sinfo->signal = iwm->wstats.qual.level;
> > + }
> > +
> > + return 0;
> > +}
> > +
> >
> > int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
> > {
> > @@ -500,6 +519,179 @@ static int iwm_cfg80211_leave_ibss(struc
> > return 0;
> > }
> >
> > +static int iwm_set_auth_type(struct iwm_priv *iwm,
> > + enum nl80211_auth_type sme_auth_type)
> > +{
> > + u8 *auth_type = &iwm->umac_profile->sec.auth_type;
> > +
> > + switch (sme_auth_type) {
> > + case NL80211_AUTHTYPE_AUTOMATIC:
> > + case NL80211_AUTHTYPE_OPEN_SYSTEM:
> > + IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
> > + *auth_type = UMAC_AUTH_TYPE_OPEN;
> > + break;
> > + case NL80211_AUTHTYPE_SHARED_KEY:
> > + if (iwm->umac_profile->sec.flags &
> > + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
> > + IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
> > + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
> > + } else {
> > + IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
> > + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
> > + }
> > +
> > + break;
> > + default:
> > + IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
> > + return -ENOTSUPP;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
> > +{
> > + if (!wpa_version) {
> > + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
> > + return 0;
> > + }
> > +
> > + if (wpa_version & NL80211_WPA_VERSION_2)
> > + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
> > +
> > + if (wpa_version & NL80211_WPA_VERSION_1)
> > + iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
> > +
> > + return 0;
> > +}
> > +
> > +static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
> > +{
> > + u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
> > + &iwm->umac_profile->sec.mcast_cipher;
> > +
> > + if (!cipher) {
> > + *profile_cipher = UMAC_CIPHER_TYPE_NONE;
> > + return 0;
> > + }
> > +
> > + switch (cipher) {
> > + case IW_AUTH_CIPHER_NONE:
> > + *profile_cipher = UMAC_CIPHER_TYPE_NONE;
> > + break;
> > + case WLAN_CIPHER_SUITE_WEP40:
> > + *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
> > + break;
> > + case WLAN_CIPHER_SUITE_WEP104:
> > + *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
> > + break;
> > + case WLAN_CIPHER_SUITE_TKIP:
> > + *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
> > + break;
> > + case WLAN_CIPHER_SUITE_CCMP:
> > + *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
> > + break;
> > + default:
> > + IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
> > + return -ENOTSUPP;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
> > +{
> > + u8 *auth_type = &iwm->umac_profile->sec.auth_type;
> > +
> > + IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
> > +
> > + if (key_mgt == WLAN_AKM_SUITE_8021X)
> > + *auth_type = UMAC_AUTH_TYPE_8021X;
> > + else if (key_mgt == WLAN_AKM_SUITE_PSK) {
> > + if (iwm->umac_profile->sec.flags &
> > + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
> > + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
> > + else
> > + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
> > + } else {
> > + IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
> > + return -EINVAL;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +
> > +static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
> > + struct cfg80211_connect_params *sme)
> > +{
> > + struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
> > + struct ieee80211_channel *chan = sme->channel;
> > + int ret;
> > +
> > + if (!test_bit(IWM_STATUS_READY, &iwm->status))
> > + return -EIO;
> > +
> > + if (!sme->ssid)
> > + return -EINVAL;
> > +
> > + if (chan)
> > + iwm->channel =
> > + ieee80211_frequency_to_channel(chan->center_freq);
> > +
> > + iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
> > + memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
> > +
> > + if (sme->bssid) {
> > + IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
> > + memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
> > + iwm->umac_profile->bss_num = 1;
> > + } else {
> > + memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
> > + iwm->umac_profile->bss_num = 0;
> > + }
> > +
> > + ret = iwm_set_auth_type(iwm, sme->auth_type);
> > + if (ret < 0)
> > + return ret;
> > +
> > + ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
> > + if (ret < 0)
> > + return ret;
> > +
> > + if (sme->crypto.n_ciphers_pairwise) {
> > + ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
> > + true);
> > + if (ret < 0)
> > + return ret;
> > + }
> > +
> > + ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
> > + if (ret < 0)
> > + return ret;
> > +
> > + if (sme->crypto.n_akm_suites) {
> > + ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
> > + if (ret < 0)
> > + return ret;
> > + }
> > +
> > + return iwm_send_mlme_profile(iwm);
> > +}
> > +
> > +static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
> > + u16 reason_code)
> > +{
> > + struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
> > +
> > + IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
> > +
> > + if (iwm->umac_profile_active)
> > + return iwm_invalidate_mlme_profile(iwm);
> > +
> > + return 0;
> > +}
> > +
> > static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
> > enum tx_power_setting type, int dbm)
> > {
> > @@ -549,8 +741,11 @@ static struct cfg80211_ops iwm_cfg80211_
> > .get_key = iwm_cfg80211_get_key,
> > .del_key = iwm_cfg80211_del_key,
> > .set_default_key = iwm_cfg80211_set_default_key,
> > + .get_station = iwm_cfg80211_get_station,
> > .scan = iwm_cfg80211_scan,
> > .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
> > + .connect = iwm_cfg80211_connect,
> > + .disconnect = iwm_cfg80211_disconnect,
> > .join_ibss = iwm_cfg80211_join_ibss,
> > .leave_ibss = iwm_cfg80211_leave_ibss,
> > .set_tx_power = iwm_cfg80211_set_txpower,
> > Index: iwm-2.6/drivers/net/wireless/iwmc3200wifi/wext.c
> > ===================================================================
> > --- iwm-2.6.orig/drivers/net/wireless/iwmc3200wifi/wext.c 2009-07-02 21:20:34.000000000 +0200
> > +++ iwm-2.6/drivers/net/wireless/iwmc3200wifi/wext.c 2009-07-03 01:18:56.000000000 +0200
> > @@ -21,31 +21,11 @@
> > *
> > */
> >
> > -#include <linux/kernel.h>
> > -#include <linux/netdevice.h>
> > #include <linux/wireless.h>
> > -#include <linux/if_arp.h>
> > -#include <linux/etherdevice.h>
> > #include <net/cfg80211.h>
> > -#include <net/iw_handler.h>
> >
> > #include "iwm.h"
> > -#include "umac.h"
> > #include "commands.h"
> > -#include "debug.h"
> > -
> > -static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
> > -{
> > - struct iwm_priv *iwm = ndev_to_iwm(dev);
> > - struct iw_statistics *wstats = &iwm->wstats;
> > -
> > - if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
> > - memset(wstats, 0, sizeof(struct iw_statistics));
> > - wstats->qual.updated = IW_QUAL_ALL_INVALID;
> > - }
> > -
> > - return wstats;
> > -}
> >
> > static int iwm_wext_siwfreq(struct net_device *dev,
> > struct iw_request_info *info,
> > @@ -53,14 +33,12 @@ static int iwm_wext_siwfreq(struct net_d
> > {
> > struct iwm_priv *iwm = ndev_to_iwm(dev);
> >
> > - if (freq->flags == IW_FREQ_AUTO)
> > - return 0;
> > -
> > - /* frequency/channel can only be set in IBSS mode */
> > - if (iwm->conf.mode != UMAC_MODE_IBSS)
> > + switch (iwm->conf.mode) {
> > + case UMAC_MODE_IBSS:
> > + return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
> > + default:
> > return -EOPNOTSUPP;
> > -
> > - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
> > + }
> > }
> >
> > static int iwm_wext_giwfreq(struct net_device *dev,
> > @@ -69,69 +47,29 @@ static int iwm_wext_giwfreq(struct net_d
> > {
> > struct iwm_priv *iwm = ndev_to_iwm(dev);
> >
> > - if (iwm->conf.mode == UMAC_MODE_IBSS)
> > + switch (iwm->conf.mode) {
> > + case UMAC_MODE_IBSS:
> > return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
> > -
> > - freq->e = 0;
> > - freq->m = iwm->channel;
> > -
> > - return 0;
> > + case UMAC_MODE_BSS:
> > + return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
> > + default:
> > + return -EOPNOTSUPP;
> > + }
> > }
> >
> > 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;
> > -
> > - IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data);
> >
> > - if (iwm->conf.mode == UMAC_MODE_IBSS)
> > + switch (iwm->conf.mode) {
> > + case UMAC_MODE_IBSS:
> > return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
> > -
> > - if (!test_bit(IWM_STATUS_READY, &iwm->status))
> > - return -EIO;
> > -
> > - if (is_zero_ether_addr(ap_addr->sa_data) ||
> > - is_broadcast_ether_addr(ap_addr->sa_data)) {
> > - IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
> > - iwm->umac_profile->bssid[0]);
> > - memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
> > - iwm->umac_profile->bss_num = 0;
> > - } else {
> > - IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
> > - ap_addr->sa_data);
> > - memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
> > - ETH_ALEN);
> > - iwm->umac_profile->bss_num = 1;
> > - }
> > -
> > - if (iwm->umac_profile_active) {
> > - int i;
> > -
> > - if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
> > - return 0;
> > -
> > - /*
> > - * 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].key_len = 0;
> > - }
> > -
> > - ret = iwm_invalidate_mlme_profile(iwm);
> > - if (ret < 0) {
> > - IWM_ERR(iwm, "Couldn't invalidate profile\n");
> > - return ret;
> > - }
> > + case UMAC_MODE_BSS:
> > + return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
> > + default:
> > + return -EOPNOTSUPP;
> > }
> > -
> > - if (iwm->umac_profile->ssid.ssid_len)
> > - return iwm_send_mlme_profile(iwm);
> > -
> > - return 0;
> > }
> >
> > static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
> > @@ -143,17 +81,10 @@ static int iwm_wext_giwap(struct net_dev
> > case UMAC_MODE_IBSS:
> > return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
> > case UMAC_MODE_BSS:
> > - if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
> > - ap_addr->sa_family = ARPHRD_ETHER;
> > - memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
> > - } else
> > - memset(&ap_addr->sa_data, 0, ETH_ALEN);
> > - break;
> > + return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
> > default:
> > return -EOPNOTSUPP;
> > }
> > -
> > - return 0;
> > }
> >
> > static int iwm_wext_siwessid(struct net_device *dev,
> > @@ -161,36 +92,15 @@ static int iwm_wext_siwessid(struct net_
> > struct iw_point *data, char *ssid)
> > {
> > struct iwm_priv *iwm = ndev_to_iwm(dev);
> > - size_t len = data->length;
> > - int ret;
> > -
> > - IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid);
> >
> > - if (iwm->conf.mode == UMAC_MODE_IBSS)
> > + switch (iwm->conf.mode) {
> > + case UMAC_MODE_IBSS:
> > return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
> > -
> > - if (!test_bit(IWM_STATUS_READY, &iwm->status))
> > - return -EIO;
> > -
> > - if (len > 0 && ssid[len - 1] == '\0')
> > - len--;
> > -
> > - if (iwm->umac_profile_active) {
> > - if (iwm->umac_profile->ssid.ssid_len == len &&
> > - !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
> > - return 0;
> > -
> > - ret = iwm_invalidate_mlme_profile(iwm);
> > - if (ret < 0) {
> > - IWM_ERR(iwm, "Couldn't invalidate profile\n");
> > - return ret;
> > - }
> > + case UMAC_MODE_BSS:
> > + return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
> > + default:
> > + return -EOPNOTSUPP;
> > }
> > -
> > - iwm->umac_profile->ssid.ssid_len = len;
> > - memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
> > -
> > - return iwm_send_mlme_profile(iwm);
> > }
> >
> > static int iwm_wext_giwessid(struct net_device *dev,
> > @@ -199,174 +109,14 @@ static int iwm_wext_giwessid(struct net_
> > {
> > struct iwm_priv *iwm = ndev_to_iwm(dev);
> >
> > - if (iwm->conf.mode == UMAC_MODE_IBSS)
> > + switch (iwm->conf.mode) {
> > + case UMAC_MODE_IBSS:
> > return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
> > -
> > - if (!test_bit(IWM_STATUS_READY, &iwm->status))
> > - return -EIO;
> > -
> > - data->length = iwm->umac_profile->ssid.ssid_len;
> > - if (data->length) {
> > - memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
> > - data->flags = 1;
> > - } else
> > - data->flags = 0;
> > -
> > - return 0;
> > -}
> > -
> > -static int iwm_wext_giwrate(struct net_device *dev,
> > - struct iw_request_info *info,
> > - struct iw_param *rate, char *extra)
> > -{
> > - struct iwm_priv *iwm = ndev_to_iwm(dev);
> > -
> > - rate->value = iwm->rate * 1000000;
> > -
> > - return 0;
> > -}
> > -
> > -static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
> > -{
> > - if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
> > - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
> > - else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
> > - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
> > - else
> > - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
> > -
> > - return 0;
> > -}
> > -
> > -static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
> > -{
> > - u8 *auth_type = &iwm->umac_profile->sec.auth_type;
> > -
> > - IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
> > -
> > - if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
> > - *auth_type = UMAC_AUTH_TYPE_8021X;
> > - else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
> > - if (iwm->umac_profile->sec.flags &
> > - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
> > - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
> > - else
> > - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
> > - } else {
> > - IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
> > - return -EINVAL;
> > - }
> > -
> > - return 0;
> > -}
> > -
> > -static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
> > -{
> > - u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
> > - &iwm->umac_profile->sec.mcast_cipher;
> > -
> > - switch (cipher) {
> > - case IW_AUTH_CIPHER_NONE:
> > - *profile_cipher = UMAC_CIPHER_TYPE_NONE;
> > - break;
> > - case IW_AUTH_CIPHER_WEP40:
> > - *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
> > - break;
> > - case IW_AUTH_CIPHER_TKIP:
> > - *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
> > - break;
> > - case IW_AUTH_CIPHER_CCMP:
> > - *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
> > - break;
> > - case IW_AUTH_CIPHER_WEP104:
> > - *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
> > - break;
> > - default:
> > - IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
> > - return -ENOTSUPP;
> > - }
> > -
> > - return 0;
> > -}
> > -
> > -static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
> > -{
> > - u8 *auth_type = &iwm->umac_profile->sec.auth_type;
> > -
> > - IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg);
> > -
> > - switch (auth_alg) {
> > - case IW_AUTH_ALG_OPEN_SYSTEM:
> > - *auth_type = UMAC_AUTH_TYPE_OPEN;
> > - break;
> > - case IW_AUTH_ALG_SHARED_KEY:
> > - if (iwm->umac_profile->sec.flags &
> > - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
> > - if (*auth_type == UMAC_AUTH_TYPE_8021X)
> > - return -EINVAL;
> > - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
> > - } else {
> > - IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n");
> > - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
> > - }
> > - break;
> > - case IW_AUTH_ALG_LEAP:
> > - default:
> > - IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
> > - return -ENOTSUPP;
> > - }
> > -
> > - return 0;
> > -}
> > -
> > -static int iwm_wext_siwauth(struct net_device *dev,
> > - struct iw_request_info *info,
> > - struct iw_param *data, char *extra)
> > -{
> > - struct iwm_priv *iwm = ndev_to_iwm(dev);
> > - int ret;
> > -
> > - if ((data->flags) &
> > - (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
> > - IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
> > - /* We need to invalidate the current profile */
> > - if (iwm->umac_profile_active) {
> > - ret = iwm_invalidate_mlme_profile(iwm);
> > - if (ret < 0) {
> > - IWM_ERR(iwm, "Couldn't invalidate profile\n");
> > - return ret;
> > - }
> > - }
> > - }
> > -
> > - switch (data->flags & IW_AUTH_INDEX) {
> > - case IW_AUTH_WPA_VERSION:
> > - return iwm_set_wpa_version(iwm, data->value);
> > - break;
> > - case IW_AUTH_CIPHER_PAIRWISE:
> > - return iwm_set_cipher(iwm, data->value, 1);
> > - break;
> > - case IW_AUTH_CIPHER_GROUP:
> > - return iwm_set_cipher(iwm, data->value, 0);
> > - break;
> > - case IW_AUTH_KEY_MGMT:
> > - return iwm_set_key_mgt(iwm, data->value);
> > - break;
> > - case IW_AUTH_80211_AUTH_ALG:
> > - return iwm_set_auth_alg(iwm, data->value);
> > - break;
> > + case UMAC_MODE_BSS:
> > + return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
> > default:
> > - return -ENOTSUPP;
> > + return -EOPNOTSUPP;
> > }
> > -
> > - return 0;
> > -}
> > -
> > -static int iwm_wext_giwauth(struct net_device *dev,
> > - struct iw_request_info *info,
> > - struct iw_param *data, char *extra)
> > -{
> > - return 0;
> > }
> >
> > static const iw_handler iwm_handlers[] =
> > @@ -404,7 +154,7 @@ static const iw_handler iwm_handlers[] =
> > (iw_handler) NULL, /* -- hole -- */
> > (iw_handler) NULL, /* -- hole -- */
> > (iw_handler) NULL, /* SIOCSIWRATE */
> > - (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
> > + (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */
> > (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
> > (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
> > (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
> > @@ -419,10 +169,10 @@ static const iw_handler iwm_handlers[] =
> > (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
> > (iw_handler) NULL, /* -- hole -- */
> > (iw_handler) NULL, /* -- hole -- */
> > - (iw_handler) NULL, /* SIOCSIWGENIE */
> > + (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
> > (iw_handler) NULL, /* SIOCGIWGENIE */
> > - (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
> > - (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
> > + (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */
> > + (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */
> > (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
> > (iw_handler) NULL, /* SIOCGIWENCODEEXT */
> > (iw_handler) NULL, /* SIOCSIWPMKSA */
> > @@ -432,6 +182,6 @@ static const iw_handler iwm_handlers[] =
> > const struct iw_handler_def iwm_iw_handler_def = {
> > .num_standard = ARRAY_SIZE(iwm_handlers),
> > .standard = (iw_handler *) iwm_handlers,
> > - .get_wireless_stats = iwm_get_wireless_stats,
> > + .get_wireless_stats = cfg80211_wireless_stats,
> > };
> >
> > Index: iwm-2.6/drivers/net/wireless/iwmc3200wifi/rx.c
> > ===================================================================
> > --- iwm-2.6.orig/drivers/net/wireless/iwmc3200wifi/rx.c 2009-07-02 21:19:58.000000000 +0200
> > +++ iwm-2.6/drivers/net/wireless/iwmc3200wifi/rx.c 2009-07-03 00:24:46.000000000 +0200
> > @@ -521,7 +521,10 @@ static int iwm_mlme_assoc_complete(struc
> >
> > iwm_link_on(iwm);
> >
> > - memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN);
> > + cfg80211_connect_result(iwm_to_ndev(iwm),
> > + complete->bssid,
> > + NULL, 0, NULL, 0,
> > + WLAN_STATUS_SUCCESS, GFP_KERNEL);
> > break;
> > case UMAC_ASSOC_COMPLETE_FAILURE:
> > clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
> > @@ -529,6 +532,11 @@ static int iwm_mlme_assoc_complete(struc
> > iwm->channel = 0;
> >
> > iwm_link_off(iwm);
> > +
> > + cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
> > + NULL, 0, NULL, 0,
> > + WLAN_STATUS_UNSPECIFIED_FAILURE,
> > + GFP_KERNEL);
> > default:
> > break;
> > }
> > @@ -538,9 +546,6 @@ static int iwm_mlme_assoc_complete(struc
> > return 0;
> > }
> >
> > - wrqu.ap_addr.sa_family = ARPHRD_ETHER;
> > - wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
> > -
> > return 0;
> > }
> >
--
Intel Open Source Technology Centre
http://oss.intel.com/
---------------------------------------------------------------------
Intel Corporation SAS (French simplified joint stock company)
Registered headquarters: "Les Montalets"- 2, rue de Paris,
92196 Meudon Cedex, France
Registration Number: 302 456 199 R.C.S. NANTERRE
Capital: 4,572,000 Euros
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
^ permalink raw reply
* Re: Memory leak in iwlwifi or false positive?
From: Catalin Marinas @ 2009-07-03 11:42 UTC (permalink / raw)
To: reinette chatre; +Cc: linux-wireless@vger.kernel.org, linux-kernel
In-Reply-To: <1246573533.17896.867.camel@rc-desk>
Hi Reinette,
On Thu, 2009-07-02 at 15:25 -0700, reinette chatre wrote:
> On Thu, 2009-07-02 at 14:32 -0700, Catalin Marinas wrote:
> > I'm trying to get kmemleak more robust and with the latest patches (not
>
> I just compiled my 2.6.31 kernel with kmemleak but did not yet look into
> how it works ... I do see a lot of messages though.
There are some patches in the latest mainline git tree to make it less
verbose and some pending patches in my kmemleak branch (on
git://linux-arm.org/linux-2.6.git).
Basically, it basically tracks all the allocated memory blocks. It scans
starting with the data sections and stacks for pointers to (anywhere
inside of) allocated memory blocks. The blocks found are scanned as well
until it finishes scanning. If a memory block wasn't referred via any
pointer during a scan, it is reported as a suspected leak (you can look
at Documentation/kmemleak.txt).
> > This happens shortly after booting. Note that if an object is freed,
> > kmemleak no longer tracks it and therefore no reporting. But in this
> > case it looks like the iwlwifi code really allocated ~4800 blocks. Is it
> > normal for this code to keep so many blocks allocated? If yes, it is
> > probably kmemleak missing some root object in the references tree.
>
> Yes - this sounds about right. You tested with 5100 hardware which by
> default initializes 20 TX queues. For each of these queues it maintains
> a 256 buffer array of commands with 356 bytes used for each command.
>
> The 20 * 256 gives me 5120 ... would that explain the ~4800?
OK, thanks. It could be a bug in kmemleak but I'll do some more testing
tonight and let you know.
It may be that I missed tracing some kmalloc calls.
Thanks.
--
Catalin
^ permalink raw reply
* Re: [PATCH v2] mac80211: minstrel: avoid accessing negative indices in rix_to_ndx()
From: Michael Buesch @ 2009-07-03 10:10 UTC (permalink / raw)
To: Johannes Berg
Cc: Luciano Coelho, linville, linux-wireless, kalle.valo,
vidhya.govindan, nbd
In-Reply-To: <1246609742.16770.54.camel@johannes.local>
On Friday 03 July 2009 10:29:02 Johannes Berg wrote:
> On Fri, 2009-07-03 at 08:25 +0300, Luciano Coelho wrote:
> > If rix is not found in mi->r[], i will become -1 after the loop. This value
> > is eventually used to access arrays, so we were accessing arrays with a
> > negative index, which is obviously not what we want to do. This patch fixes
> > this potential problem.
>
> This seems odd -- are you or are you not saying that this can happen in
> normal operation?
>
> > @@ -66,7 +66,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
> > for (i = rix; i >= 0; i--)
> > if (mi->r[i].rix == rix)
> > break;
> > - WARN_ON(mi->r[i].rix != rix);
> > + WARN_ON(i < 0);
> > return i;
>
> If it can, this warning seems wrong.
Well, the old WARN_ON seems wrong anyway, because it accesses the array
out of bounds. In case the loop did not find the entry, the warn on will look like this:
WARN_ON(mi->r[-1].rix != rix);
So I do think it's correct to replace the WARN_ON with WARN_ON(i < 0), if this can't
happen in normal operation. If it can happen in normal op, the warning should be removed
and the callers of rix_to_ndx() need to be checked.
--
Greetings, Michael.
^ permalink raw reply
* Re: [PATCH v2] mac80211: minstrel: avoid accessing negative indices in rix_to_ndx()
From: Luciano Coelho @ 2009-07-03 8:44 UTC (permalink / raw)
To: ext Johannes Berg
Cc: linville@tuxdriver.org, linux-wireless@vger.kernel.org,
Valo Kalle (Nokia-D/Tampere), Govindan Vidhya (Nokia-D/Tampere),
nbd@openwrt.org
In-Reply-To: <1246609742.16770.54.camel@johannes.local>
ext Johannes Berg wrote:
> On Fri, 2009-07-03 at 08:25 +0300, Luciano Coelho wrote:
>
>> If rix is not found in mi->r[], i will become -1 after the loop. This value
>> is eventually used to access arrays, so we were accessing arrays with a
>> negative index, which is obviously not what we want to do. This patch fixes
>> this potential problem.
>>
>
> This seems odd -- are you or are you not saying that this can happen in
> normal operation?
>
This should *not* happen in normal operation, but it was happening due
to a bug elsewhere (which has already been fixed).
>> @@ -66,7 +66,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
>> for (i = rix; i >= 0; i--)
>> if (mi->r[i].rix == rix)
>> break;
>> - WARN_ON(mi->r[i].rix != rix);
>> + WARN_ON(i < 0);
>> return i;
>>
>
> If it can, this warning seems wrong.
>
We were reaching this WARN_ON on our device some time ago, before we
backported some other minstrel fixes from upstream. So this patch
doesn't fix an *active* bug, but it makes things more robust in case
there is a bug elsewhere. It is not good at all to access mi->r[-1],
especially the code later which writes to this array and could
potentially overwrite somebody else's memory.
--
Cheers,
Luca.
^ permalink raw reply
* Re: [PATCH v2] mac80211: minstrel: avoid accessing negative indices in rix_to_ndx()
From: Johannes Berg @ 2009-07-03 8:29 UTC (permalink / raw)
To: Luciano Coelho; +Cc: linville, linux-wireless, kalle.valo, vidhya.govindan, nbd
In-Reply-To: <1246598708-5594-1-git-send-email-luciano.coelho@nokia.com>
[-- Attachment #1: Type: text/plain, Size: 687 bytes --]
On Fri, 2009-07-03 at 08:25 +0300, Luciano Coelho wrote:
> If rix is not found in mi->r[], i will become -1 after the loop. This value
> is eventually used to access arrays, so we were accessing arrays with a
> negative index, which is obviously not what we want to do. This patch fixes
> this potential problem.
This seems odd -- are you or are you not saying that this can happen in
normal operation?
> @@ -66,7 +66,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
> for (i = rix; i >= 0; i--)
> if (mi->r[i].rix == rix)
> break;
> - WARN_ON(mi->r[i].rix != rix);
> + WARN_ON(i < 0);
> return i;
If it can, this warning seems wrong.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Memory leak in iwlwifi or false positive?
From: Catalin Marinas @ 2009-07-02 21:32 UTC (permalink / raw)
To: linux-wireless, linux-kernel
Hi,
I'm trying to get kmemleak more robust and with the latest patches (not
pushed yet) it seems to no longer show so many random leaks. However, I
get a lot of leaks reported in the iwlwifi code, about 4800 and they do
not disappear from any subsequent memory scanning (as is usually the
case with false positives). There are a lot of kmalloc's of < 512 bytes
and /proc/slabinfo seems to be in line with this:
kmalloc-512 5440 5481
This happens shortly after booting. Note that if an object is freed,
kmemleak no longer tracks it and therefore no reporting. But in this
case it looks like the iwlwifi code really allocated ~4800 blocks. Is it
normal for this code to keep so many blocks allocated? If yes, it is
probably kmemleak missing some root object in the references tree.
I'm not familiar with this code so any help is greatly appreciated.
The majority of kmemleak traces look like this:
unreferenced object 0xc1be3d40 (size 512):
comm "iwlagn", pid 1571, jiffies 4294903229
backtrace:
[<c01e1f0b>] kmemleak_alloc+0x14b/0x290
[<c01db2e5>] __kmalloc+0x125/0x1e0
[<f95c77ef>] iwl_tx_queue_init+0x3f/0x310 [iwlcore]
[<f95c9276>] iwl_txq_ctx_reset+0x206/0x5a0 [iwlcore]
[<f95c199a>] iwl_hw_nic_init+0xba/0x110 [iwlcore]
[<f9765263>] __iwl_up+0xb3/0x340 [iwlagn]
[<f9765d72>] iwl_bg_up+0x32/0x50 [iwlagn]
[<c0150d7d>] worker_thread+0x1ad/0x2d0
[<c01555dc>] kthread+0x7c/0x90
[<c0103cb7>] kernel_thread_helper+0x7/0x10
[<ffffffff>] 0xffffffff
For a full kmemleak log and dmesg, see:
http://homepage.ntlworld.com/cmarinas/kmemleak-3
http://homepage.ntlworld.com/cmarinas/dmesg-3
Thanks.
--
Catalin
^ permalink raw reply
* Re: [PATCH] iwmc3200wifi: cfg80211 managed mode port
From: Johannes Berg @ 2009-07-03 8:02 UTC (permalink / raw)
To: Samuel Ortiz; +Cc: Zhu, Yi, John Linville, linux-wireless@vger.kernel.org
In-Reply-To: <20090702235513.GA4143@sortiz.org>
[-- Attachment #1: Type: text/plain, Size: 21676 bytes --]
On Fri, 2009-07-03 at 01:55 +0200, Samuel Ortiz wrote:
> This patch ports iwm to the new cfg80211 managed mode API.
> Whenever those managed mode routines get combined with the ibss one, we will
> just have to entirely get rid of the wext implementation (We may have to only
> keep the iw_handler until cfg80211 does the wext registration for us).
Looks good. I'll take care of the combine part later.
johannes
> Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
> ---
> drivers/net/wireless/iwmc3200wifi/cfg80211.c | 195 ++++++++++++++++
> drivers/net/wireless/iwmc3200wifi/rx.c | 13 -
> drivers/net/wireless/iwmc3200wifi/wext.c | 320 ++-------------------------
> 3 files changed, 239 insertions(+), 289 deletions(-)
>
> Index: iwm-2.6/drivers/net/wireless/iwmc3200wifi/cfg80211.c
> ===================================================================
> --- iwm-2.6.orig/drivers/net/wireless/iwmc3200wifi/cfg80211.c 2009-07-02 21:20:34.000000000 +0200
> +++ iwm-2.6/drivers/net/wireless/iwmc3200wifi/cfg80211.c 2009-07-03 01:43:09.000000000 +0200
> @@ -305,6 +305,25 @@ static int iwm_cfg80211_set_default_key(
> return iwm_reset_profile(iwm);
> }
>
> +int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
> + u8 *mac, struct station_info *sinfo)
> +{
> + struct iwm_priv *iwm = ndev_to_iwm(ndev);
> +
> + if (memcmp(mac, iwm->bssid, ETH_ALEN))
> + return -ENOENT;
> +
> + sinfo->filled |= STATION_INFO_TX_BITRATE;
> + sinfo->txrate.legacy = iwm->rate * 10;
> +
> + if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
> + sinfo->filled |= STATION_INFO_SIGNAL;
> + sinfo->signal = iwm->wstats.qual.level;
> + }
> +
> + return 0;
> +}
> +
>
> int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
> {
> @@ -500,6 +519,179 @@ static int iwm_cfg80211_leave_ibss(struc
> return 0;
> }
>
> +static int iwm_set_auth_type(struct iwm_priv *iwm,
> + enum nl80211_auth_type sme_auth_type)
> +{
> + u8 *auth_type = &iwm->umac_profile->sec.auth_type;
> +
> + switch (sme_auth_type) {
> + case NL80211_AUTHTYPE_AUTOMATIC:
> + case NL80211_AUTHTYPE_OPEN_SYSTEM:
> + IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
> + *auth_type = UMAC_AUTH_TYPE_OPEN;
> + break;
> + case NL80211_AUTHTYPE_SHARED_KEY:
> + if (iwm->umac_profile->sec.flags &
> + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
> + IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
> + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
> + } else {
> + IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
> + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
> + }
> +
> + break;
> + default:
> + IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
> + return -ENOTSUPP;
> + }
> +
> + return 0;
> +}
> +
> +static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
> +{
> + if (!wpa_version) {
> + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
> + return 0;
> + }
> +
> + if (wpa_version & NL80211_WPA_VERSION_2)
> + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
> +
> + if (wpa_version & NL80211_WPA_VERSION_1)
> + iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
> +
> + return 0;
> +}
> +
> +static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
> +{
> + u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
> + &iwm->umac_profile->sec.mcast_cipher;
> +
> + if (!cipher) {
> + *profile_cipher = UMAC_CIPHER_TYPE_NONE;
> + return 0;
> + }
> +
> + switch (cipher) {
> + case IW_AUTH_CIPHER_NONE:
> + *profile_cipher = UMAC_CIPHER_TYPE_NONE;
> + break;
> + case WLAN_CIPHER_SUITE_WEP40:
> + *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
> + break;
> + case WLAN_CIPHER_SUITE_WEP104:
> + *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
> + break;
> + case WLAN_CIPHER_SUITE_TKIP:
> + *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
> + break;
> + case WLAN_CIPHER_SUITE_CCMP:
> + *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
> + break;
> + default:
> + IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
> + return -ENOTSUPP;
> + }
> +
> + return 0;
> +}
> +
> +static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
> +{
> + u8 *auth_type = &iwm->umac_profile->sec.auth_type;
> +
> + IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
> +
> + if (key_mgt == WLAN_AKM_SUITE_8021X)
> + *auth_type = UMAC_AUTH_TYPE_8021X;
> + else if (key_mgt == WLAN_AKM_SUITE_PSK) {
> + if (iwm->umac_profile->sec.flags &
> + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
> + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
> + else
> + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
> + } else {
> + IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +
> +static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
> + struct cfg80211_connect_params *sme)
> +{
> + struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
> + struct ieee80211_channel *chan = sme->channel;
> + int ret;
> +
> + if (!test_bit(IWM_STATUS_READY, &iwm->status))
> + return -EIO;
> +
> + if (!sme->ssid)
> + return -EINVAL;
> +
> + if (chan)
> + iwm->channel =
> + ieee80211_frequency_to_channel(chan->center_freq);
> +
> + iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
> + memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
> +
> + if (sme->bssid) {
> + IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
> + memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
> + iwm->umac_profile->bss_num = 1;
> + } else {
> + memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
> + iwm->umac_profile->bss_num = 0;
> + }
> +
> + ret = iwm_set_auth_type(iwm, sme->auth_type);
> + if (ret < 0)
> + return ret;
> +
> + ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
> + if (ret < 0)
> + return ret;
> +
> + if (sme->crypto.n_ciphers_pairwise) {
> + ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
> + true);
> + if (ret < 0)
> + return ret;
> + }
> +
> + ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
> + if (ret < 0)
> + return ret;
> +
> + if (sme->crypto.n_akm_suites) {
> + ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
> + if (ret < 0)
> + return ret;
> + }
> +
> + return iwm_send_mlme_profile(iwm);
> +}
> +
> +static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
> + u16 reason_code)
> +{
> + struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
> +
> + IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
> +
> + if (iwm->umac_profile_active)
> + return iwm_invalidate_mlme_profile(iwm);
> +
> + return 0;
> +}
> +
> static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
> enum tx_power_setting type, int dbm)
> {
> @@ -549,8 +741,11 @@ static struct cfg80211_ops iwm_cfg80211_
> .get_key = iwm_cfg80211_get_key,
> .del_key = iwm_cfg80211_del_key,
> .set_default_key = iwm_cfg80211_set_default_key,
> + .get_station = iwm_cfg80211_get_station,
> .scan = iwm_cfg80211_scan,
> .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
> + .connect = iwm_cfg80211_connect,
> + .disconnect = iwm_cfg80211_disconnect,
> .join_ibss = iwm_cfg80211_join_ibss,
> .leave_ibss = iwm_cfg80211_leave_ibss,
> .set_tx_power = iwm_cfg80211_set_txpower,
> Index: iwm-2.6/drivers/net/wireless/iwmc3200wifi/wext.c
> ===================================================================
> --- iwm-2.6.orig/drivers/net/wireless/iwmc3200wifi/wext.c 2009-07-02 21:20:34.000000000 +0200
> +++ iwm-2.6/drivers/net/wireless/iwmc3200wifi/wext.c 2009-07-03 01:18:56.000000000 +0200
> @@ -21,31 +21,11 @@
> *
> */
>
> -#include <linux/kernel.h>
> -#include <linux/netdevice.h>
> #include <linux/wireless.h>
> -#include <linux/if_arp.h>
> -#include <linux/etherdevice.h>
> #include <net/cfg80211.h>
> -#include <net/iw_handler.h>
>
> #include "iwm.h"
> -#include "umac.h"
> #include "commands.h"
> -#include "debug.h"
> -
> -static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
> -{
> - struct iwm_priv *iwm = ndev_to_iwm(dev);
> - struct iw_statistics *wstats = &iwm->wstats;
> -
> - if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
> - memset(wstats, 0, sizeof(struct iw_statistics));
> - wstats->qual.updated = IW_QUAL_ALL_INVALID;
> - }
> -
> - return wstats;
> -}
>
> static int iwm_wext_siwfreq(struct net_device *dev,
> struct iw_request_info *info,
> @@ -53,14 +33,12 @@ static int iwm_wext_siwfreq(struct net_d
> {
> struct iwm_priv *iwm = ndev_to_iwm(dev);
>
> - if (freq->flags == IW_FREQ_AUTO)
> - return 0;
> -
> - /* frequency/channel can only be set in IBSS mode */
> - if (iwm->conf.mode != UMAC_MODE_IBSS)
> + switch (iwm->conf.mode) {
> + case UMAC_MODE_IBSS:
> + return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
> + default:
> return -EOPNOTSUPP;
> -
> - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
> + }
> }
>
> static int iwm_wext_giwfreq(struct net_device *dev,
> @@ -69,69 +47,29 @@ static int iwm_wext_giwfreq(struct net_d
> {
> struct iwm_priv *iwm = ndev_to_iwm(dev);
>
> - if (iwm->conf.mode == UMAC_MODE_IBSS)
> + switch (iwm->conf.mode) {
> + case UMAC_MODE_IBSS:
> return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
> -
> - freq->e = 0;
> - freq->m = iwm->channel;
> -
> - return 0;
> + case UMAC_MODE_BSS:
> + return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
> + default:
> + return -EOPNOTSUPP;
> + }
> }
>
> 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;
> -
> - IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data);
>
> - if (iwm->conf.mode == UMAC_MODE_IBSS)
> + switch (iwm->conf.mode) {
> + case UMAC_MODE_IBSS:
> return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
> -
> - if (!test_bit(IWM_STATUS_READY, &iwm->status))
> - return -EIO;
> -
> - if (is_zero_ether_addr(ap_addr->sa_data) ||
> - is_broadcast_ether_addr(ap_addr->sa_data)) {
> - IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
> - iwm->umac_profile->bssid[0]);
> - memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
> - iwm->umac_profile->bss_num = 0;
> - } else {
> - IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
> - ap_addr->sa_data);
> - memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
> - ETH_ALEN);
> - iwm->umac_profile->bss_num = 1;
> - }
> -
> - if (iwm->umac_profile_active) {
> - int i;
> -
> - if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
> - return 0;
> -
> - /*
> - * 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].key_len = 0;
> - }
> -
> - ret = iwm_invalidate_mlme_profile(iwm);
> - if (ret < 0) {
> - IWM_ERR(iwm, "Couldn't invalidate profile\n");
> - return ret;
> - }
> + case UMAC_MODE_BSS:
> + return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
> + default:
> + return -EOPNOTSUPP;
> }
> -
> - if (iwm->umac_profile->ssid.ssid_len)
> - return iwm_send_mlme_profile(iwm);
> -
> - return 0;
> }
>
> static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
> @@ -143,17 +81,10 @@ static int iwm_wext_giwap(struct net_dev
> case UMAC_MODE_IBSS:
> return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
> case UMAC_MODE_BSS:
> - if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
> - ap_addr->sa_family = ARPHRD_ETHER;
> - memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
> - } else
> - memset(&ap_addr->sa_data, 0, ETH_ALEN);
> - break;
> + return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
> default:
> return -EOPNOTSUPP;
> }
> -
> - return 0;
> }
>
> static int iwm_wext_siwessid(struct net_device *dev,
> @@ -161,36 +92,15 @@ static int iwm_wext_siwessid(struct net_
> struct iw_point *data, char *ssid)
> {
> struct iwm_priv *iwm = ndev_to_iwm(dev);
> - size_t len = data->length;
> - int ret;
> -
> - IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid);
>
> - if (iwm->conf.mode == UMAC_MODE_IBSS)
> + switch (iwm->conf.mode) {
> + case UMAC_MODE_IBSS:
> return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
> -
> - if (!test_bit(IWM_STATUS_READY, &iwm->status))
> - return -EIO;
> -
> - if (len > 0 && ssid[len - 1] == '\0')
> - len--;
> -
> - if (iwm->umac_profile_active) {
> - if (iwm->umac_profile->ssid.ssid_len == len &&
> - !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
> - return 0;
> -
> - ret = iwm_invalidate_mlme_profile(iwm);
> - if (ret < 0) {
> - IWM_ERR(iwm, "Couldn't invalidate profile\n");
> - return ret;
> - }
> + case UMAC_MODE_BSS:
> + return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
> + default:
> + return -EOPNOTSUPP;
> }
> -
> - iwm->umac_profile->ssid.ssid_len = len;
> - memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
> -
> - return iwm_send_mlme_profile(iwm);
> }
>
> static int iwm_wext_giwessid(struct net_device *dev,
> @@ -199,174 +109,14 @@ static int iwm_wext_giwessid(struct net_
> {
> struct iwm_priv *iwm = ndev_to_iwm(dev);
>
> - if (iwm->conf.mode == UMAC_MODE_IBSS)
> + switch (iwm->conf.mode) {
> + case UMAC_MODE_IBSS:
> return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
> -
> - if (!test_bit(IWM_STATUS_READY, &iwm->status))
> - return -EIO;
> -
> - data->length = iwm->umac_profile->ssid.ssid_len;
> - if (data->length) {
> - memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
> - data->flags = 1;
> - } else
> - data->flags = 0;
> -
> - return 0;
> -}
> -
> -static int iwm_wext_giwrate(struct net_device *dev,
> - struct iw_request_info *info,
> - struct iw_param *rate, char *extra)
> -{
> - struct iwm_priv *iwm = ndev_to_iwm(dev);
> -
> - rate->value = iwm->rate * 1000000;
> -
> - return 0;
> -}
> -
> -static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
> -{
> - if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
> - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
> - else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
> - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
> - else
> - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
> -
> - return 0;
> -}
> -
> -static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
> -{
> - u8 *auth_type = &iwm->umac_profile->sec.auth_type;
> -
> - IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
> -
> - if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
> - *auth_type = UMAC_AUTH_TYPE_8021X;
> - else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
> - if (iwm->umac_profile->sec.flags &
> - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
> - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
> - else
> - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
> - } else {
> - IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
> - return -EINVAL;
> - }
> -
> - return 0;
> -}
> -
> -static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
> -{
> - u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
> - &iwm->umac_profile->sec.mcast_cipher;
> -
> - switch (cipher) {
> - case IW_AUTH_CIPHER_NONE:
> - *profile_cipher = UMAC_CIPHER_TYPE_NONE;
> - break;
> - case IW_AUTH_CIPHER_WEP40:
> - *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
> - break;
> - case IW_AUTH_CIPHER_TKIP:
> - *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
> - break;
> - case IW_AUTH_CIPHER_CCMP:
> - *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
> - break;
> - case IW_AUTH_CIPHER_WEP104:
> - *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
> - break;
> - default:
> - IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
> - return -ENOTSUPP;
> - }
> -
> - return 0;
> -}
> -
> -static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
> -{
> - u8 *auth_type = &iwm->umac_profile->sec.auth_type;
> -
> - IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg);
> -
> - switch (auth_alg) {
> - case IW_AUTH_ALG_OPEN_SYSTEM:
> - *auth_type = UMAC_AUTH_TYPE_OPEN;
> - break;
> - case IW_AUTH_ALG_SHARED_KEY:
> - if (iwm->umac_profile->sec.flags &
> - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
> - if (*auth_type == UMAC_AUTH_TYPE_8021X)
> - return -EINVAL;
> - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
> - } else {
> - IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n");
> - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
> - }
> - break;
> - case IW_AUTH_ALG_LEAP:
> - default:
> - IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
> - return -ENOTSUPP;
> - }
> -
> - return 0;
> -}
> -
> -static int iwm_wext_siwauth(struct net_device *dev,
> - struct iw_request_info *info,
> - struct iw_param *data, char *extra)
> -{
> - struct iwm_priv *iwm = ndev_to_iwm(dev);
> - int ret;
> -
> - if ((data->flags) &
> - (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
> - IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
> - /* We need to invalidate the current profile */
> - if (iwm->umac_profile_active) {
> - ret = iwm_invalidate_mlme_profile(iwm);
> - if (ret < 0) {
> - IWM_ERR(iwm, "Couldn't invalidate profile\n");
> - return ret;
> - }
> - }
> - }
> -
> - switch (data->flags & IW_AUTH_INDEX) {
> - case IW_AUTH_WPA_VERSION:
> - return iwm_set_wpa_version(iwm, data->value);
> - break;
> - case IW_AUTH_CIPHER_PAIRWISE:
> - return iwm_set_cipher(iwm, data->value, 1);
> - break;
> - case IW_AUTH_CIPHER_GROUP:
> - return iwm_set_cipher(iwm, data->value, 0);
> - break;
> - case IW_AUTH_KEY_MGMT:
> - return iwm_set_key_mgt(iwm, data->value);
> - break;
> - case IW_AUTH_80211_AUTH_ALG:
> - return iwm_set_auth_alg(iwm, data->value);
> - break;
> + case UMAC_MODE_BSS:
> + return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
> default:
> - return -ENOTSUPP;
> + return -EOPNOTSUPP;
> }
> -
> - return 0;
> -}
> -
> -static int iwm_wext_giwauth(struct net_device *dev,
> - struct iw_request_info *info,
> - struct iw_param *data, char *extra)
> -{
> - return 0;
> }
>
> static const iw_handler iwm_handlers[] =
> @@ -404,7 +154,7 @@ static const iw_handler iwm_handlers[] =
> (iw_handler) NULL, /* -- hole -- */
> (iw_handler) NULL, /* -- hole -- */
> (iw_handler) NULL, /* SIOCSIWRATE */
> - (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
> + (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */
> (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
> (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
> (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
> @@ -419,10 +169,10 @@ static const iw_handler iwm_handlers[] =
> (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
> (iw_handler) NULL, /* -- hole -- */
> (iw_handler) NULL, /* -- hole -- */
> - (iw_handler) NULL, /* SIOCSIWGENIE */
> + (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
> (iw_handler) NULL, /* SIOCGIWGENIE */
> - (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
> - (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
> + (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */
> + (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */
> (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
> (iw_handler) NULL, /* SIOCGIWENCODEEXT */
> (iw_handler) NULL, /* SIOCSIWPMKSA */
> @@ -432,6 +182,6 @@ static const iw_handler iwm_handlers[] =
> const struct iw_handler_def iwm_iw_handler_def = {
> .num_standard = ARRAY_SIZE(iwm_handlers),
> .standard = (iw_handler *) iwm_handlers,
> - .get_wireless_stats = iwm_get_wireless_stats,
> + .get_wireless_stats = cfg80211_wireless_stats,
> };
>
> Index: iwm-2.6/drivers/net/wireless/iwmc3200wifi/rx.c
> ===================================================================
> --- iwm-2.6.orig/drivers/net/wireless/iwmc3200wifi/rx.c 2009-07-02 21:19:58.000000000 +0200
> +++ iwm-2.6/drivers/net/wireless/iwmc3200wifi/rx.c 2009-07-03 00:24:46.000000000 +0200
> @@ -521,7 +521,10 @@ static int iwm_mlme_assoc_complete(struc
>
> iwm_link_on(iwm);
>
> - memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN);
> + cfg80211_connect_result(iwm_to_ndev(iwm),
> + complete->bssid,
> + NULL, 0, NULL, 0,
> + WLAN_STATUS_SUCCESS, GFP_KERNEL);
> break;
> case UMAC_ASSOC_COMPLETE_FAILURE:
> clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
> @@ -529,6 +532,11 @@ static int iwm_mlme_assoc_complete(struc
> iwm->channel = 0;
>
> iwm_link_off(iwm);
> +
> + cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
> + NULL, 0, NULL, 0,
> + WLAN_STATUS_UNSPECIFIED_FAILURE,
> + GFP_KERNEL);
> default:
> break;
> }
> @@ -538,9 +546,6 @@ static int iwm_mlme_assoc_complete(struc
> return 0;
> }
>
> - wrqu.ap_addr.sa_family = ARPHRD_ETHER;
> - wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
> -
> return 0;
> }
>
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH] cfg80211: check for current_bss from giwrate
From: Johannes Berg @ 2009-07-03 8:01 UTC (permalink / raw)
To: Samuel Ortiz; +Cc: John Linville, linux-wireless@vger.kernel.org
In-Reply-To: <20090703000044.GB4143@sortiz.org>
[-- Attachment #1: Type: text/plain, Size: 1238 bytes --]
On Fri, 2009-07-03 at 02:00 +0200, Samuel Ortiz wrote:
> When connecting to an ESSID manually, we may not set the BSSID, and thus
> wdev->wext.connect.bssid will be NULL.
> wdev->current_bss is always updated when a connection is established so we
> should check it first.
Indeed, good catch
Acked-by: Johannes Berg <johannes@sipsolutions.net>
> Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
> ---
> net/wireless/wext-compat.c | 7 +++++--
> 1 file changed, 5 insertions(+), 2 deletions(-)
>
> Index: iwm-2.6/net/wireless/wext-compat.c
> ===================================================================
> --- iwm-2.6.orig/net/wireless/wext-compat.c 2009-07-03 01:40:09.000000000 +0200
> +++ iwm-2.6/net/wireless/wext-compat.c 2009-07-03 01:40:18.000000000 +0200
> @@ -1137,8 +1137,11 @@ int cfg80211_wext_giwrate(struct net_dev
> if (!rdev->ops->get_station)
> return -EOPNOTSUPP;
>
> - addr = wdev->wext.connect.bssid;
> - if (!addr)
> + if (wdev->current_bss)
> + addr = wdev->current_bss->bssid;
> + else if (wdev->wext.connect.bssid)
> + addr = wdev->wext.connect.bssid;
> + else
> return -ENOTSUPP;
>
> err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo);
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: mac80211: Force beacon update?
From: Johannes Berg @ 2009-07-03 8:00 UTC (permalink / raw)
To: Reiner Herrmann; +Cc: linux-wireless
In-Reply-To: <4A4DB01E.2030408@informatik.uni-kl.de>
[-- Attachment #1: Type: text/plain, Size: 205 bytes --]
On Fri, 2009-07-03 at 09:15 +0200, Reiner Herrmann wrote:
> I want to attach a custom IE to beacons,
Umm, afaik you can configure that in hostapd, if not then you need to
hack hostapd.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: mac80211: Force beacon update?
From: Iwo Mergler @ 2009-07-03 7:29 UTC (permalink / raw)
To: Reiner Herrmann; +Cc: linux-wireless
In-Reply-To: <4A4DB01E.2030408@informatik.uni-kl.de>
Reiner Herrmann wrote:
> Hi,
>
> I want to attach a custom IE to beacons, but some drivers (like b43)
> are fetching their beacons via ieee80211_beacon_get() only once and
> retransmit this beacon every time.
> Some other drivers (like mac80211_hwsim, ath9k) are calling it
> before every beacon transmission.
>
> Is there a general way to make all drivers generate new beacons instead
> of caching them or would I have to adapt them?
> If adapting drivers is the only way, do you have any suggestions on
> how to do that?
Hi Reiner
the drivers that call ieee80211_beacon_get() only once, have
hardware that transmits beacons automatically. That is, the
beacon template from ieee80211_beacon_get() is stored in the
hardware and the hardware then automatically sends that while
updating a few fields as needed.
In other words, the driver doesn't know anything about the
beacons after the initial setup, and thus can't call ieee80211_beacon_get().
No caching is involved. :-)
So to do what you want, you need to disable the automatic
beaconing and use packet injection and send your beacons
as raw frames.
Best regards,
Iwo
^ permalink raw reply
* mac80211: Force beacon update?
From: Reiner Herrmann @ 2009-07-03 7:15 UTC (permalink / raw)
To: linux-wireless
Hi,
I want to attach a custom IE to beacons, but some drivers (like b43)
are fetching their beacons via ieee80211_beacon_get() only once and
retransmit this beacon every time.
Some other drivers (like mac80211_hwsim, ath9k) are calling it
before every beacon transmission.
Is there a general way to make all drivers generate new beacons instead
of caching them or would I have to adapt them?
If adapting drivers is the only way, do you have any suggestions on
how to do that?
Thank you for your answers.
Regards,
Reiner
^ permalink raw reply
* [PATCH v2] mac80211: minstrel: avoid accessing negative indices in rix_to_ndx()
From: Luciano Coelho @ 2009-07-03 5:25 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, johannes, kalle.valo, vidhya.govindan, nbd
If rix is not found in mi->r[], i will become -1 after the loop. This value
is eventually used to access arrays, so we were accessing arrays with a
negative index, which is obviously not what we want to do. This patch fixes
this potential problem.
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Acked-by: Felix Fietkau <nbd@openwrt.org>
---
net/mac80211/rc80211_minstrel.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index b218b98..37771ab 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -66,7 +66,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
for (i = rix; i >= 0; i--)
if (mi->r[i].rix == rix)
break;
- WARN_ON(mi->r[i].rix != rix);
+ WARN_ON(i < 0);
return i;
}
@@ -181,6 +181,9 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
break;
ndx = rix_to_ndx(mi, ar[i].idx);
+ if (ndx < 0)
+ continue;
+
mi->r[ndx].attempts += ar[i].count;
if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
--
1.6.0.4
^ permalink raw reply related
* Re: [PATCH] mac80211: minstrel: avoid accessing negative indices in rix_to_ndx()
From: Luciano Coelho @ 2009-07-03 5:15 UTC (permalink / raw)
To: ext Felix Fietkau
Cc: linville@tuxdriver.org, linux-wireless@vger.kernel.org,
johannes@sipsolutions.net, Valo Kalle (Nokia-D/Tampere),
Govindan Vidhya (Nokia-D/Tampere)
In-Reply-To: <4A4D4DC6.30502@openwrt.org>
ext Felix Fietkau wrote:
> Luciano Coelho wrote:
>
>> If rix is not found in mi->r[], i will become -1 after the loop. This value
>> is eventually used to access arrays, so we were accessing arrays with a
>> negative index, which is obviously not what we want to do. This patch fixes
>> this potential problem.
>>
>> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
>> ---
>> net/mac80211/rc80211_minstrel.c | 5 ++++-
>> 1 files changed, 4 insertions(+), 1 deletions(-)
>>
>> diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
>> index b218b98..e2dd248 100644
>> --- a/net/mac80211/rc80211_minstrel.c
>> +++ b/net/mac80211/rc80211_minstrel.c
>> @@ -66,7 +66,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
>> for (i = rix; i >= 0; i--)
>> if (mi->r[i].rix == rix)
>> break;
>> - WARN_ON(mi->r[i].rix != rix);
>> + WARN_ON(i < 0 || mi->r[i].rix != rix);
>>
> I believe this line could be changed to WARN_ON(i < 0), because
> (mi->r[i].rix != rix) will never be true unless i < 0.
> Probably not that important though.
>
That's true. I'll change the code and send v2. It's not that
important, but it is code that will never be reached, so it should be
removed.
> Acked-by: Felix Fietkau <nbd@openwrt.org>
>
Thanks!
--
Cheers,
Luca.
^ permalink raw reply
* Re: [PATCH] mac80211: minstrel: avoid accessing negative indices in rix_to_ndx()
From: Felix Fietkau @ 2009-07-03 0:16 UTC (permalink / raw)
To: Luciano Coelho
Cc: linville, linux-wireless, johannes, kalle.valo, vidhya.govindan
In-Reply-To: <1246571549-29014-1-git-send-email-luciano.coelho@nokia.com>
Luciano Coelho wrote:
> If rix is not found in mi->r[], i will become -1 after the loop. This value
> is eventually used to access arrays, so we were accessing arrays with a
> negative index, which is obviously not what we want to do. This patch fixes
> this potential problem.
>
> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
> ---
> net/mac80211/rc80211_minstrel.c | 5 ++++-
> 1 files changed, 4 insertions(+), 1 deletions(-)
>
> diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
> index b218b98..e2dd248 100644
> --- a/net/mac80211/rc80211_minstrel.c
> +++ b/net/mac80211/rc80211_minstrel.c
> @@ -66,7 +66,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
> for (i = rix; i >= 0; i--)
> if (mi->r[i].rix == rix)
> break;
> - WARN_ON(mi->r[i].rix != rix);
> + WARN_ON(i < 0 || mi->r[i].rix != rix);
I believe this line could be changed to WARN_ON(i < 0), because
(mi->r[i].rix != rix) will never be true unless i < 0.
Probably not that important though.
Acked-by: Felix Fietkau <nbd@openwrt.org>
- Felix
^ permalink raw reply
* [PATCH] cfg80211: check for current_bss from giwrate
From: Samuel Ortiz @ 2009-07-03 0:00 UTC (permalink / raw)
To: Johannes Berg; +Cc: John Linville, linux-wireless@vger.kernel.org
In-Reply-To: <20090701193421.155074452@sipsolutions.net>
When connecting to an ESSID manually, we may not set the BSSID, and thus
wdev->wext.connect.bssid will be NULL.
wdev->current_bss is always updated when a connection is established so we
should check it first.
Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
---
net/wireless/wext-compat.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
Index: iwm-2.6/net/wireless/wext-compat.c
===================================================================
--- iwm-2.6.orig/net/wireless/wext-compat.c 2009-07-03 01:40:09.000000000 +0200
+++ iwm-2.6/net/wireless/wext-compat.c 2009-07-03 01:40:18.000000000 +0200
@@ -1137,8 +1137,11 @@ int cfg80211_wext_giwrate(struct net_dev
if (!rdev->ops->get_station)
return -EOPNOTSUPP;
- addr = wdev->wext.connect.bssid;
- if (!addr)
+ if (wdev->current_bss)
+ addr = wdev->current_bss->bssid;
+ else if (wdev->wext.connect.bssid)
+ addr = wdev->wext.connect.bssid;
+ else
return -ENOTSUPP;
err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo);
--
Intel Open Source Technology Centre
http://oss.intel.com/
---------------------------------------------------------------------
Intel Corporation SAS (French simplified joint stock company)
Registered headquarters: "Les Montalets"- 2, rue de Paris,
92196 Meudon Cedex, France
Registration Number: 302 456 199 R.C.S. NANTERRE
Capital: 4,572,000 Euros
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
^ permalink raw reply
* [PATCH] iwmc3200wifi: cfg80211 managed mode port
From: Samuel Ortiz @ 2009-07-02 23:55 UTC (permalink / raw)
To: Johannes Berg, Zhu, Yi; +Cc: John Linville, linux-wireless@vger.kernel.org
In-Reply-To: <20090701193421.155074452@sipsolutions.net>
This patch ports iwm to the new cfg80211 managed mode API.
Whenever those managed mode routines get combined with the ibss one, we will
just have to entirely get rid of the wext implementation (We may have to only
keep the iw_handler until cfg80211 does the wext registration for us).
Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
---
drivers/net/wireless/iwmc3200wifi/cfg80211.c | 195 ++++++++++++++++
drivers/net/wireless/iwmc3200wifi/rx.c | 13 -
drivers/net/wireless/iwmc3200wifi/wext.c | 320 ++-------------------------
3 files changed, 239 insertions(+), 289 deletions(-)
Index: iwm-2.6/drivers/net/wireless/iwmc3200wifi/cfg80211.c
===================================================================
--- iwm-2.6.orig/drivers/net/wireless/iwmc3200wifi/cfg80211.c 2009-07-02 21:20:34.000000000 +0200
+++ iwm-2.6/drivers/net/wireless/iwmc3200wifi/cfg80211.c 2009-07-03 01:43:09.000000000 +0200
@@ -305,6 +305,25 @@ static int iwm_cfg80211_set_default_key(
return iwm_reset_profile(iwm);
}
+int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+ if (memcmp(mac, iwm->bssid, ETH_ALEN))
+ return -ENOENT;
+
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = iwm->rate * 10;
+
+ if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = iwm->wstats.qual.level;
+ }
+
+ return 0;
+}
+
int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
{
@@ -500,6 +519,179 @@ static int iwm_cfg80211_leave_ibss(struc
return 0;
}
+static int iwm_set_auth_type(struct iwm_priv *iwm,
+ enum nl80211_auth_type sme_auth_type)
+{
+ u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+ switch (sme_auth_type) {
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
+ *auth_type = UMAC_AUTH_TYPE_OPEN;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ if (iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
+ IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
+ *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+ } else {
+ IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
+ *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+ }
+
+ break;
+ default:
+ IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
+{
+ if (!wpa_version) {
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
+ return 0;
+ }
+
+ if (wpa_version & NL80211_WPA_VERSION_2)
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
+
+ if (wpa_version & NL80211_WPA_VERSION_1)
+ iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
+
+ return 0;
+}
+
+static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
+{
+ u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
+ &iwm->umac_profile->sec.mcast_cipher;
+
+ if (!cipher) {
+ *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+ return 0;
+ }
+
+ switch (cipher) {
+ case IW_AUTH_CIPHER_NONE:
+ *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
+ break;
+ default:
+ IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
+{
+ u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+ IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
+
+ if (key_mgt == WLAN_AKM_SUITE_8021X)
+ *auth_type = UMAC_AUTH_TYPE_8021X;
+ else if (key_mgt == WLAN_AKM_SUITE_PSK) {
+ if (iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
+ *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+ else
+ *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+ } else {
+ IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ struct ieee80211_channel *chan = sme->channel;
+ int ret;
+
+ if (!test_bit(IWM_STATUS_READY, &iwm->status))
+ return -EIO;
+
+ if (!sme->ssid)
+ return -EINVAL;
+
+ if (chan)
+ iwm->channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+
+ iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
+ memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
+
+ if (sme->bssid) {
+ IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
+ memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
+ iwm->umac_profile->bss_num = 1;
+ } else {
+ memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
+ iwm->umac_profile->bss_num = 0;
+ }
+
+ ret = iwm_set_auth_type(iwm, sme->auth_type);
+ if (ret < 0)
+ return ret;
+
+ ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
+ true);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_akm_suites) {
+ ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+ IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
+
+ if (iwm->umac_profile_active)
+ return iwm_invalidate_mlme_profile(iwm);
+
+ return 0;
+}
+
static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
enum tx_power_setting type, int dbm)
{
@@ -549,8 +741,11 @@ static struct cfg80211_ops iwm_cfg80211_
.get_key = iwm_cfg80211_get_key,
.del_key = iwm_cfg80211_del_key,
.set_default_key = iwm_cfg80211_set_default_key,
+ .get_station = iwm_cfg80211_get_station,
.scan = iwm_cfg80211_scan,
.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
+ .connect = iwm_cfg80211_connect,
+ .disconnect = iwm_cfg80211_disconnect,
.join_ibss = iwm_cfg80211_join_ibss,
.leave_ibss = iwm_cfg80211_leave_ibss,
.set_tx_power = iwm_cfg80211_set_txpower,
Index: iwm-2.6/drivers/net/wireless/iwmc3200wifi/wext.c
===================================================================
--- iwm-2.6.orig/drivers/net/wireless/iwmc3200wifi/wext.c 2009-07-02 21:20:34.000000000 +0200
+++ iwm-2.6/drivers/net/wireless/iwmc3200wifi/wext.c 2009-07-03 01:18:56.000000000 +0200
@@ -21,31 +21,11 @@
*
*/
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
#include <linux/wireless.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
#include <net/cfg80211.h>
-#include <net/iw_handler.h>
#include "iwm.h"
-#include "umac.h"
#include "commands.h"
-#include "debug.h"
-
-static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iw_statistics *wstats = &iwm->wstats;
-
- if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
- memset(wstats, 0, sizeof(struct iw_statistics));
- wstats->qual.updated = IW_QUAL_ALL_INVALID;
- }
-
- return wstats;
-}
static int iwm_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
@@ -53,14 +33,12 @@ static int iwm_wext_siwfreq(struct net_d
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (freq->flags == IW_FREQ_AUTO)
- return 0;
-
- /* frequency/channel can only be set in IBSS mode */
- if (iwm->conf.mode != UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
+ return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+ default:
return -EOPNOTSUPP;
-
- return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+ }
}
static int iwm_wext_giwfreq(struct net_device *dev,
@@ -69,69 +47,29 @@ static int iwm_wext_giwfreq(struct net_d
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
-
- freq->e = 0;
- freq->m = iwm->channel;
-
- return 0;
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
+ default:
+ return -EOPNOTSUPP;
+ }
}
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;
-
- IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data);
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- if (is_zero_ether_addr(ap_addr->sa_data) ||
- is_broadcast_ether_addr(ap_addr->sa_data)) {
- IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
- iwm->umac_profile->bssid[0]);
- memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
- iwm->umac_profile->bss_num = 0;
- } else {
- IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
- ap_addr->sa_data);
- memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
- ETH_ALEN);
- iwm->umac_profile->bss_num = 1;
- }
-
- if (iwm->umac_profile_active) {
- int i;
-
- if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
- return 0;
-
- /*
- * 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].key_len = 0;
- }
-
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
+ default:
+ return -EOPNOTSUPP;
}
-
- if (iwm->umac_profile->ssid.ssid_len)
- return iwm_send_mlme_profile(iwm);
-
- return 0;
}
static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
@@ -143,17 +81,10 @@ static int iwm_wext_giwap(struct net_dev
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
case UMAC_MODE_BSS:
- if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
- ap_addr->sa_family = ARPHRD_ETHER;
- memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
- } else
- memset(&ap_addr->sa_data, 0, ETH_ALEN);
- break;
+ return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
default:
return -EOPNOTSUPP;
}
-
- return 0;
}
static int iwm_wext_siwessid(struct net_device *dev,
@@ -161,36 +92,15 @@ static int iwm_wext_siwessid(struct net_
struct iw_point *data, char *ssid)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- size_t len = data->length;
- int ret;
-
- IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid);
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- if (len > 0 && ssid[len - 1] == '\0')
- len--;
-
- if (iwm->umac_profile_active) {
- if (iwm->umac_profile->ssid.ssid_len == len &&
- !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
- return 0;
-
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
+ default:
+ return -EOPNOTSUPP;
}
-
- iwm->umac_profile->ssid.ssid_len = len;
- memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
-
- return iwm_send_mlme_profile(iwm);
}
static int iwm_wext_giwessid(struct net_device *dev,
@@ -199,174 +109,14 @@ static int iwm_wext_giwessid(struct net_
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- data->length = iwm->umac_profile->ssid.ssid_len;
- if (data->length) {
- memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
- data->flags = 1;
- } else
- data->flags = 0;
-
- return 0;
-}
-
-static int iwm_wext_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- rate->value = iwm->rate * 1000000;
-
- return 0;
-}
-
-static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
-{
- if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
- else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
- else
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
-
- return 0;
-}
-
-static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
-{
- u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
- IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
-
- if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
- *auth_type = UMAC_AUTH_TYPE_8021X;
- else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
- if (iwm->umac_profile->sec.flags &
- (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
- *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
- else
- *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- } else {
- IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
-{
- u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
- &iwm->umac_profile->sec.mcast_cipher;
-
- switch (cipher) {
- case IW_AUTH_CIPHER_NONE:
- *profile_cipher = UMAC_CIPHER_TYPE_NONE;
- break;
- case IW_AUTH_CIPHER_WEP40:
- *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
- break;
- case IW_AUTH_CIPHER_TKIP:
- *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
- break;
- case IW_AUTH_CIPHER_CCMP:
- *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
- break;
- case IW_AUTH_CIPHER_WEP104:
- *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
- break;
- default:
- IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
-{
- u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
- IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg);
-
- switch (auth_alg) {
- case IW_AUTH_ALG_OPEN_SYSTEM:
- *auth_type = UMAC_AUTH_TYPE_OPEN;
- break;
- case IW_AUTH_ALG_SHARED_KEY:
- if (iwm->umac_profile->sec.flags &
- (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
- if (*auth_type == UMAC_AUTH_TYPE_8021X)
- return -EINVAL;
- *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
- } else {
- IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n");
- *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- }
- break;
- case IW_AUTH_ALG_LEAP:
- default:
- IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- int ret;
-
- if ((data->flags) &
- (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
- IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
- /* We need to invalidate the current profile */
- if (iwm->umac_profile_active) {
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
- }
- }
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- return iwm_set_wpa_version(iwm, data->value);
- break;
- case IW_AUTH_CIPHER_PAIRWISE:
- return iwm_set_cipher(iwm, data->value, 1);
- break;
- case IW_AUTH_CIPHER_GROUP:
- return iwm_set_cipher(iwm, data->value, 0);
- break;
- case IW_AUTH_KEY_MGMT:
- return iwm_set_key_mgt(iwm, data->value);
- break;
- case IW_AUTH_80211_AUTH_ALG:
- return iwm_set_auth_alg(iwm, data->value);
- break;
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
default:
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
-
- return 0;
-}
-
-static int iwm_wext_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- return 0;
}
static const iw_handler iwm_handlers[] =
@@ -404,7 +154,7 @@ static const iw_handler iwm_handlers[] =
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* SIOCSIWRATE */
- (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
+ (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */
(iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
(iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
(iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
@@ -419,10 +169,10 @@ static const iw_handler iwm_handlers[] =
(iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWGENIE */
+ (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
(iw_handler) NULL, /* SIOCGIWGENIE */
- (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
- (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
+ (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */
+ (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */
(iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
(iw_handler) NULL, /* SIOCGIWENCODEEXT */
(iw_handler) NULL, /* SIOCSIWPMKSA */
@@ -432,6 +182,6 @@ static const iw_handler iwm_handlers[] =
const struct iw_handler_def iwm_iw_handler_def = {
.num_standard = ARRAY_SIZE(iwm_handlers),
.standard = (iw_handler *) iwm_handlers,
- .get_wireless_stats = iwm_get_wireless_stats,
+ .get_wireless_stats = cfg80211_wireless_stats,
};
Index: iwm-2.6/drivers/net/wireless/iwmc3200wifi/rx.c
===================================================================
--- iwm-2.6.orig/drivers/net/wireless/iwmc3200wifi/rx.c 2009-07-02 21:19:58.000000000 +0200
+++ iwm-2.6/drivers/net/wireless/iwmc3200wifi/rx.c 2009-07-03 00:24:46.000000000 +0200
@@ -521,7 +521,10 @@ static int iwm_mlme_assoc_complete(struc
iwm_link_on(iwm);
- memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN);
+ cfg80211_connect_result(iwm_to_ndev(iwm),
+ complete->bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_SUCCESS, GFP_KERNEL);
break;
case UMAC_ASSOC_COMPLETE_FAILURE:
clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -529,6 +532,11 @@ static int iwm_mlme_assoc_complete(struc
iwm->channel = 0;
iwm_link_off(iwm);
+
+ cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
default:
break;
}
@@ -538,9 +546,6 @@ static int iwm_mlme_assoc_complete(struc
return 0;
}
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
-
return 0;
}
--
Intel Open Source Technology Centre
http://oss.intel.com/
---------------------------------------------------------------------
Intel Corporation SAS (French simplified joint stock company)
Registered headquarters: "Les Montalets"- 2, rue de Paris,
92196 Meudon Cedex, France
Registration Number: 302 456 199 R.C.S. NANTERRE
Capital: 4,572,000 Euros
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
^ permalink raw reply
* Re: Memory leak in iwlwifi or false positive?
From: reinette chatre @ 2009-07-02 22:25 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-wireless@vger.kernel.org, linux-kernel
In-Reply-To: <1246570323.24044.16.camel@pc1117.cambridge.arm.com>
Hi Catalin,
On Thu, 2009-07-02 at 14:32 -0700, Catalin Marinas wrote:
> Hi,
>
> I'm trying to get kmemleak more robust and with the latest patches (not
I just compiled my 2.6.31 kernel with kmemleak but did not yet look into
how it works ... I do see a lot of messages though.
> pushed yet) it seems to no longer show so many random leaks. However, I
> get a lot of leaks reported in the iwlwifi code, about 4800 and they do
> not disappear from any subsequent memory scanning (as is usually the
> case with false positives). There are a lot of kmalloc's of < 512 bytes
> and /proc/slabinfo seems to be in line with this:
>
> kmalloc-512 5440 5481
>
> This happens shortly after booting. Note that if an object is freed,
> kmemleak no longer tracks it and therefore no reporting. But in this
> case it looks like the iwlwifi code really allocated ~4800 blocks. Is it
> normal for this code to keep so many blocks allocated? If yes, it is
> probably kmemleak missing some root object in the references tree.
Yes - this sounds about right. You tested with 5100 hardware which by
default initializes 20 TX queues. For each of these queues it maintains
a 256 buffer array of commands with 356 bytes used for each command.
The 20 * 256 gives me 5120 ... would that explain the ~4800?
Reinette
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox