diff options
author | James Ketrenos <jketreno@linux.intel.com> | 2005-08-24 22:56:24 -0400 |
---|---|---|
committer | James Ketrenos <jketreno@linux.intel.com> | 2005-11-07 18:49:56 -0500 |
commit | c848d0af404f00835f038e370005733d90a186fd (patch) | |
tree | e9d3e4b02fa9404f7a9633d98e3a35468eb516be /drivers/net | |
parent | a613bffd3aac89bb0a8c9b7afa72af9b0ae30f0a (diff) |
Catch ipw2200 up to equivelancy with v1.0.3
* Fix #616 problem with OOPS on module load (thanks to Yi Zhu)
* Fixed problem with led module parameter being described as
'auto_create'
* Added support to merge between adhoc networks (thanks to Mohamed Abbas)
* Added semaphore lock at the driver's entry points to protect against
re-entry (thanks to Mohamed Abbas)
* Added semaphore lock to background scheduled driver actions (thanks to
Mohamed Abbas)
* Changed how signal quality is reported for scan output (thanks to
Peter Jones)
* Fixed how high/low clamp values of signal quality are reported so a
more consistent ramp is provided (thanks to Bill Moss)
* Fix #624 problem with duplicate addresses (again) (thanks to Bernard
Blackham)
* Fix #385 problem with fragmentation and certain sized packets (thanks
to Mohamed Abbas)
* Modified iwconfig network name if RF kill is enabled to say 'radio off'
* Fix #382 problem with driver not responding to probe requests in Ad-Hoc
mode (thanks to Mohamed Abbas)
Signed-off-by: James Ketrenos <jketreno@linux.intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ipw2200.c | 841 | ||||
-rw-r--r-- | drivers/net/wireless/ipw2200.h | 5 |
2 files changed, 668 insertions, 178 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index ea7a3dcf1daa..0bf1931ac5f3 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | #include "ipw2200.h" | 33 | #include "ipw2200.h" |
34 | 34 | ||
35 | #define IPW2200_VERSION "1.0.2" | 35 | #define IPW2200_VERSION "1.0.3" |
36 | #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" | 36 | #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" |
37 | #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" | 37 | #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" |
38 | #define DRV_VERSION IPW2200_VERSION | 38 | #define DRV_VERSION IPW2200_VERSION |
@@ -68,9 +68,10 @@ static void ipw_tx_queue_free(struct ipw_priv *); | |||
68 | static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *); | 68 | static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *); |
69 | static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *); | 69 | static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *); |
70 | static void ipw_rx_queue_replenish(void *); | 70 | static void ipw_rx_queue_replenish(void *); |
71 | |||
72 | static int ipw_up(struct ipw_priv *); | 71 | static int ipw_up(struct ipw_priv *); |
72 | static void ipw_bg_up(void *); | ||
73 | static void ipw_down(struct ipw_priv *); | 73 | static void ipw_down(struct ipw_priv *); |
74 | static void ipw_bg_down(void *); | ||
74 | static int ipw_config(struct ipw_priv *); | 75 | static int ipw_config(struct ipw_priv *); |
75 | static int init_supported_rates(struct ipw_priv *priv, | 76 | static int init_supported_rates(struct ipw_priv *priv, |
76 | struct ipw_supported_rates *prates); | 77 | struct ipw_supported_rates *prates); |
@@ -473,6 +474,11 @@ static void ipw_dump_nic_event_log(struct ipw_priv *priv) | |||
473 | } | 474 | } |
474 | } | 475 | } |
475 | 476 | ||
477 | static inline int ipw_is_init(struct ipw_priv *priv) | ||
478 | { | ||
479 | return (priv->status & STATUS_INIT) ? 1 : 0; | ||
480 | } | ||
481 | |||
476 | static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len) | 482 | static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len) |
477 | { | 483 | { |
478 | u32 addr, field_info, field_len, field_count, total_len; | 484 | u32 addr, field_info, field_len, field_count, total_len; |
@@ -698,6 +704,14 @@ void ipw_led_link_on(struct ipw_priv *priv) | |||
698 | spin_unlock_irqrestore(&priv->lock, flags); | 704 | spin_unlock_irqrestore(&priv->lock, flags); |
699 | } | 705 | } |
700 | 706 | ||
707 | static void ipw_bg_led_link_on(void *data) | ||
708 | { | ||
709 | struct ipw_priv *priv = data; | ||
710 | down(&priv->sem); | ||
711 | ipw_led_link_on(data); | ||
712 | up(&priv->sem); | ||
713 | } | ||
714 | |||
701 | void ipw_led_link_off(struct ipw_priv *priv) | 715 | void ipw_led_link_off(struct ipw_priv *priv) |
702 | { | 716 | { |
703 | unsigned long flags; | 717 | unsigned long flags; |
@@ -734,6 +748,14 @@ void ipw_led_link_off(struct ipw_priv *priv) | |||
734 | spin_unlock_irqrestore(&priv->lock, flags); | 748 | spin_unlock_irqrestore(&priv->lock, flags); |
735 | } | 749 | } |
736 | 750 | ||
751 | static void ipw_bg_led_link_off(void *data) | ||
752 | { | ||
753 | struct ipw_priv *priv = data; | ||
754 | down(&priv->sem); | ||
755 | ipw_led_link_off(data); | ||
756 | up(&priv->sem); | ||
757 | } | ||
758 | |||
737 | void ipw_led_activity_on(struct ipw_priv *priv) | 759 | void ipw_led_activity_on(struct ipw_priv *priv) |
738 | { | 760 | { |
739 | unsigned long flags; | 761 | unsigned long flags; |
@@ -762,6 +784,7 @@ void ipw_led_activity_on(struct ipw_priv *priv) | |||
762 | 784 | ||
763 | priv->status |= STATUS_LED_ACT_ON; | 785 | priv->status |= STATUS_LED_ACT_ON; |
764 | 786 | ||
787 | cancel_delayed_work(&priv->led_act_off); | ||
765 | queue_delayed_work(priv->workqueue, &priv->led_act_off, | 788 | queue_delayed_work(priv->workqueue, &priv->led_act_off, |
766 | LD_TIME_ACT_ON); | 789 | LD_TIME_ACT_ON); |
767 | } else { | 790 | } else { |
@@ -801,13 +824,22 @@ void ipw_led_activity_off(struct ipw_priv *priv) | |||
801 | spin_unlock_irqrestore(&priv->lock, flags); | 824 | spin_unlock_irqrestore(&priv->lock, flags); |
802 | } | 825 | } |
803 | 826 | ||
827 | static void ipw_bg_led_activity_off(void *data) | ||
828 | { | ||
829 | struct ipw_priv *priv = data; | ||
830 | down(&priv->sem); | ||
831 | ipw_led_activity_off(data); | ||
832 | up(&priv->sem); | ||
833 | } | ||
834 | |||
804 | void ipw_led_band_on(struct ipw_priv *priv) | 835 | void ipw_led_band_on(struct ipw_priv *priv) |
805 | { | 836 | { |
806 | unsigned long flags; | 837 | unsigned long flags; |
807 | u32 led; | 838 | u32 led; |
808 | 839 | ||
809 | /* Only nic type 1 supports mode LEDs */ | 840 | /* Only nic type 1 supports mode LEDs */ |
810 | if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1) | 841 | if (priv->config & CFG_NO_LED || |
842 | priv->nic_type != EEPROM_NIC_TYPE_1 || !priv->assoc_network) | ||
811 | return; | 843 | return; |
812 | 844 | ||
813 | spin_lock_irqsave(&priv->lock, flags); | 845 | spin_lock_irqsave(&priv->lock, flags); |
@@ -993,7 +1025,9 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, | |||
993 | const char *buf, size_t count) | 1025 | const char *buf, size_t count) |
994 | { | 1026 | { |
995 | struct ipw_priv *priv = dev_get_drvdata(d); | 1027 | struct ipw_priv *priv = dev_get_drvdata(d); |
1028 | #ifdef CONFIG_IPW_DEBUG | ||
996 | struct net_device *dev = priv->net_dev; | 1029 | struct net_device *dev = priv->net_dev; |
1030 | #endif | ||
997 | char buffer[] = "00000000"; | 1031 | char buffer[] = "00000000"; |
998 | unsigned long len = | 1032 | unsigned long len = |
999 | (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; | 1033 | (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; |
@@ -1704,6 +1738,14 @@ static void ipw_adapter_restart(void *adapter) | |||
1704 | } | 1738 | } |
1705 | } | 1739 | } |
1706 | 1740 | ||
1741 | static void ipw_bg_adapter_restart(void *data) | ||
1742 | { | ||
1743 | struct ipw_priv *priv = data; | ||
1744 | down(&priv->sem); | ||
1745 | ipw_adapter_restart(data); | ||
1746 | up(&priv->sem); | ||
1747 | } | ||
1748 | |||
1707 | #define IPW_SCAN_CHECK_WATCHDOG (5 * HZ) | 1749 | #define IPW_SCAN_CHECK_WATCHDOG (5 * HZ) |
1708 | 1750 | ||
1709 | static void ipw_scan_check(void *data) | 1751 | static void ipw_scan_check(void *data) |
@@ -1717,6 +1759,14 @@ static void ipw_scan_check(void *data) | |||
1717 | } | 1759 | } |
1718 | } | 1760 | } |
1719 | 1761 | ||
1762 | static void ipw_bg_scan_check(void *data) | ||
1763 | { | ||
1764 | struct ipw_priv *priv = data; | ||
1765 | down(&priv->sem); | ||
1766 | ipw_scan_check(data); | ||
1767 | up(&priv->sem); | ||
1768 | } | ||
1769 | |||
1720 | static int ipw_send_scan_request_ext(struct ipw_priv *priv, | 1770 | static int ipw_send_scan_request_ext(struct ipw_priv *priv, |
1721 | struct ipw_scan_request_ext *request) | 1771 | struct ipw_scan_request_ext *request) |
1722 | { | 1772 | { |
@@ -2982,6 +3032,8 @@ static int ipw_load(struct ipw_priv *priv) | |||
2982 | 3032 | ||
2983 | /* Ensure interrupts are disabled */ | 3033 | /* Ensure interrupts are disabled */ |
2984 | ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL); | 3034 | ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL); |
3035 | /* ack pending interrupts */ | ||
3036 | ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL); | ||
2985 | 3037 | ||
2986 | /* kick start the device */ | 3038 | /* kick start the device */ |
2987 | ipw_start_nic(priv); | 3039 | ipw_start_nic(priv); |
@@ -3350,9 +3402,21 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) | |||
3350 | 3402 | ||
3351 | } | 3403 | } |
3352 | 3404 | ||
3353 | static void ipw_disassociate(void *data) | 3405 | static int ipw_disassociate(void *data) |
3354 | { | 3406 | { |
3407 | struct ipw_priv *priv = data; | ||
3408 | if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) | ||
3409 | return 0; | ||
3355 | ipw_send_disassociate(data, 0); | 3410 | ipw_send_disassociate(data, 0); |
3411 | return 1; | ||
3412 | } | ||
3413 | |||
3414 | static void ipw_bg_disassociate(void *data) | ||
3415 | { | ||
3416 | struct ipw_priv *priv = data; | ||
3417 | down(&priv->sem); | ||
3418 | ipw_disassociate(data); | ||
3419 | up(&priv->sem); | ||
3356 | } | 3420 | } |
3357 | 3421 | ||
3358 | struct ipw_status_code { | 3422 | struct ipw_status_code { |
@@ -3571,8 +3635,6 @@ static u32 ipw_get_current_rate(struct ipw_priv *priv) | |||
3571 | return 0; | 3635 | return 0; |
3572 | } | 3636 | } |
3573 | 3637 | ||
3574 | #define PERFECT_RSSI (-20) | ||
3575 | #define WORST_RSSI (-85) | ||
3576 | #define IPW_STATS_INTERVAL (2 * HZ) | 3638 | #define IPW_STATS_INTERVAL (2 * HZ) |
3577 | static void ipw_gather_stats(struct ipw_priv *priv) | 3639 | static void ipw_gather_stats(struct ipw_priv *priv) |
3578 | { | 3640 | { |
@@ -3663,19 +3725,19 @@ static void ipw_gather_stats(struct ipw_priv *priv) | |||
3663 | tx_quality, tx_failures_delta, tx_packets_delta); | 3725 | tx_quality, tx_failures_delta, tx_packets_delta); |
3664 | 3726 | ||
3665 | rssi = average_value(&priv->average_rssi); | 3727 | rssi = average_value(&priv->average_rssi); |
3666 | if (rssi > PERFECT_RSSI) | 3728 | signal_quality = |
3729 | (100 * | ||
3730 | (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) * | ||
3731 | (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) - | ||
3732 | (priv->ieee->perfect_rssi - rssi) * | ||
3733 | (15 * (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) + | ||
3734 | 62 * (priv->ieee->perfect_rssi - rssi))) / | ||
3735 | ((priv->ieee->perfect_rssi - priv->ieee->worst_rssi) * | ||
3736 | (priv->ieee->perfect_rssi - priv->ieee->worst_rssi)); | ||
3737 | if (signal_quality > 100) | ||
3667 | signal_quality = 100; | 3738 | signal_quality = 100; |
3668 | else if (rssi < WORST_RSSI) | 3739 | else if (signal_quality < 1) |
3669 | signal_quality = 0; | 3740 | signal_quality = 0; |
3670 | else /* qual = 100a^2 - 15ab + 62b^2 / a^2 */ | ||
3671 | signal_quality = | ||
3672 | (100 * | ||
3673 | (PERFECT_RSSI - WORST_RSSI) * | ||
3674 | (PERFECT_RSSI - WORST_RSSI) - | ||
3675 | (PERFECT_RSSI - rssi) * | ||
3676 | (15 * (PERFECT_RSSI - WORST_RSSI) + | ||
3677 | 62 * (PERFECT_RSSI - rssi))) / | ||
3678 | ((PERFECT_RSSI - WORST_RSSI) * (PERFECT_RSSI - WORST_RSSI)); | ||
3679 | 3741 | ||
3680 | IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", | 3742 | IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", |
3681 | signal_quality, rssi); | 3743 | signal_quality, rssi); |
@@ -3705,6 +3767,14 @@ static void ipw_gather_stats(struct ipw_priv *priv) | |||
3705 | IPW_STATS_INTERVAL); | 3767 | IPW_STATS_INTERVAL); |
3706 | } | 3768 | } |
3707 | 3769 | ||
3770 | static void ipw_bg_gather_stats(void *data) | ||
3771 | { | ||
3772 | struct ipw_priv *priv = data; | ||
3773 | down(&priv->sem); | ||
3774 | ipw_gather_stats(data); | ||
3775 | up(&priv->sem); | ||
3776 | } | ||
3777 | |||
3708 | static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, | 3778 | static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, |
3709 | int missed_count) | 3779 | int missed_count) |
3710 | { | 3780 | { |
@@ -4456,6 +4526,14 @@ static void ipw_rx_queue_replenish(void *data) | |||
4456 | ipw_rx_queue_restock(priv); | 4526 | ipw_rx_queue_restock(priv); |
4457 | } | 4527 | } |
4458 | 4528 | ||
4529 | static void ipw_bg_rx_queue_replenish(void *data) | ||
4530 | { | ||
4531 | struct ipw_priv *priv = data; | ||
4532 | down(&priv->sem); | ||
4533 | ipw_rx_queue_replenish(data); | ||
4534 | up(&priv->sem); | ||
4535 | } | ||
4536 | |||
4459 | /* Assumes that the skb field of the buffers in 'pool' is kept accurate. | 4537 | /* Assumes that the skb field of the buffers in 'pool' is kept accurate. |
4460 | * If an SKB has been detached, the POOL needs to have it's SKB set to NULL | 4538 | * If an SKB has been detached, the POOL needs to have it's SKB set to NULL |
4461 | * This free routine walks the list of POOL entries and if SKB is set to | 4539 | * This free routine walks the list of POOL entries and if SKB is set to |
@@ -4715,6 +4793,215 @@ struct ipw_network_match { | |||
4715 | struct ipw_supported_rates rates; | 4793 | struct ipw_supported_rates rates; |
4716 | }; | 4794 | }; |
4717 | 4795 | ||
4796 | static int ipw_find_adhoc_network(struct ipw_priv *priv, | ||
4797 | struct ipw_network_match *match, | ||
4798 | struct ieee80211_network *network, | ||
4799 | int roaming) | ||
4800 | { | ||
4801 | struct ipw_supported_rates rates; | ||
4802 | |||
4803 | /* Verify that this network's capability is compatible with the | ||
4804 | * current mode (AdHoc or Infrastructure) */ | ||
4805 | if ((priv->ieee->iw_mode == IW_MODE_ADHOC && | ||
4806 | !(network->capability & WLAN_CAPABILITY_IBSS))) { | ||
4807 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded due to " | ||
4808 | "capability mismatch.\n", | ||
4809 | escape_essid(network->ssid, network->ssid_len), | ||
4810 | MAC_ARG(network->bssid)); | ||
4811 | return 0; | ||
4812 | } | ||
4813 | |||
4814 | /* If we do not have an ESSID for this AP, we can not associate with | ||
4815 | * it */ | ||
4816 | if (network->flags & NETWORK_EMPTY_ESSID) { | ||
4817 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " | ||
4818 | "because of hidden ESSID.\n", | ||
4819 | escape_essid(network->ssid, network->ssid_len), | ||
4820 | MAC_ARG(network->bssid)); | ||
4821 | return 0; | ||
4822 | } | ||
4823 | |||
4824 | if (unlikely(roaming)) { | ||
4825 | /* If we are roaming, then ensure check if this is a valid | ||
4826 | * network to try and roam to */ | ||
4827 | if ((network->ssid_len != match->network->ssid_len) || | ||
4828 | memcmp(network->ssid, match->network->ssid, | ||
4829 | network->ssid_len)) { | ||
4830 | IPW_DEBUG_MERGE("Netowrk '%s (" MAC_FMT ")' excluded " | ||
4831 | "because of non-network ESSID.\n", | ||
4832 | escape_essid(network->ssid, | ||
4833 | network->ssid_len), | ||
4834 | MAC_ARG(network->bssid)); | ||
4835 | return 0; | ||
4836 | } | ||
4837 | } else { | ||
4838 | /* If an ESSID has been configured then compare the broadcast | ||
4839 | * ESSID to ours */ | ||
4840 | if ((priv->config & CFG_STATIC_ESSID) && | ||
4841 | ((network->ssid_len != priv->essid_len) || | ||
4842 | memcmp(network->ssid, priv->essid, | ||
4843 | min(network->ssid_len, priv->essid_len)))) { | ||
4844 | char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; | ||
4845 | strncpy(escaped, | ||
4846 | escape_essid(network->ssid, network->ssid_len), | ||
4847 | sizeof(escaped)); | ||
4848 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " | ||
4849 | "because of ESSID mismatch: '%s'.\n", | ||
4850 | escaped, MAC_ARG(network->bssid), | ||
4851 | escape_essid(priv->essid, | ||
4852 | priv->essid_len)); | ||
4853 | return 0; | ||
4854 | } | ||
4855 | } | ||
4856 | |||
4857 | /* If the old network rate is better than this one, don't bother | ||
4858 | * testing everything else. */ | ||
4859 | |||
4860 | if (network->time_stamp[0] < match->network->time_stamp[0]) { | ||
4861 | IPW_DEBUG_MERGE | ||
4862 | ("Network '%s excluded because newer than current network.\n", | ||
4863 | escape_essid(match->network->ssid, | ||
4864 | match->network->ssid_len)); | ||
4865 | return 0; | ||
4866 | } else if (network->time_stamp[1] < match->network->time_stamp[1]) { | ||
4867 | IPW_DEBUG_MERGE | ||
4868 | ("Network '%s excluded because newer than current network.\n", | ||
4869 | escape_essid(match->network->ssid, | ||
4870 | match->network->ssid_len)); | ||
4871 | return 0; | ||
4872 | } | ||
4873 | |||
4874 | /* Now go through and see if the requested network is valid... */ | ||
4875 | if (priv->ieee->scan_age != 0 && | ||
4876 | time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { | ||
4877 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " | ||
4878 | "because of age: %lums.\n", | ||
4879 | escape_essid(network->ssid, network->ssid_len), | ||
4880 | MAC_ARG(network->bssid), | ||
4881 | (jiffies - network->last_scanned) / (HZ / 100)); | ||
4882 | return 0; | ||
4883 | } | ||
4884 | |||
4885 | if ((priv->config & CFG_STATIC_CHANNEL) && | ||
4886 | (network->channel != priv->channel)) { | ||
4887 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " | ||
4888 | "because of channel mismatch: %d != %d.\n", | ||
4889 | escape_essid(network->ssid, network->ssid_len), | ||
4890 | MAC_ARG(network->bssid), | ||
4891 | network->channel, priv->channel); | ||
4892 | return 0; | ||
4893 | } | ||
4894 | |||
4895 | /* Verify privacy compatability */ | ||
4896 | if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != | ||
4897 | ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { | ||
4898 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " | ||
4899 | "because of privacy mismatch: %s != %s.\n", | ||
4900 | escape_essid(network->ssid, network->ssid_len), | ||
4901 | MAC_ARG(network->bssid), | ||
4902 | priv->capability & CAP_PRIVACY_ON ? "on" : | ||
4903 | "off", | ||
4904 | network->capability & | ||
4905 | WLAN_CAPABILITY_PRIVACY ? "on" : "off"); | ||
4906 | return 0; | ||
4907 | } | ||
4908 | |||
4909 | if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { | ||
4910 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " | ||
4911 | "because of the same BSSID match: " MAC_FMT | ||
4912 | ".\n", escape_essid(network->ssid, | ||
4913 | network->ssid_len), | ||
4914 | MAC_ARG(network->bssid), MAC_ARG(priv->bssid)); | ||
4915 | return 0; | ||
4916 | } | ||
4917 | |||
4918 | /* Filter out any incompatible freq / mode combinations */ | ||
4919 | if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { | ||
4920 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " | ||
4921 | "because of invalid frequency/mode " | ||
4922 | "combination.\n", | ||
4923 | escape_essid(network->ssid, network->ssid_len), | ||
4924 | MAC_ARG(network->bssid)); | ||
4925 | return 0; | ||
4926 | } | ||
4927 | |||
4928 | /* Ensure that the rates supported by the driver are compatible with | ||
4929 | * this AP, including verification of basic rates (mandatory) */ | ||
4930 | if (!ipw_compatible_rates(priv, network, &rates)) { | ||
4931 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " | ||
4932 | "because configured rate mask excludes " | ||
4933 | "AP mandatory rate.\n", | ||
4934 | escape_essid(network->ssid, network->ssid_len), | ||
4935 | MAC_ARG(network->bssid)); | ||
4936 | return 0; | ||
4937 | } | ||
4938 | |||
4939 | if (rates.num_rates == 0) { | ||
4940 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " | ||
4941 | "because of no compatible rates.\n", | ||
4942 | escape_essid(network->ssid, network->ssid_len), | ||
4943 | MAC_ARG(network->bssid)); | ||
4944 | return 0; | ||
4945 | } | ||
4946 | |||
4947 | /* TODO: Perform any further minimal comparititive tests. We do not | ||
4948 | * want to put too much policy logic here; intelligent scan selection | ||
4949 | * should occur within a generic IEEE 802.11 user space tool. */ | ||
4950 | |||
4951 | /* Set up 'new' AP to this network */ | ||
4952 | ipw_copy_rates(&match->rates, &rates); | ||
4953 | match->network = network; | ||
4954 | IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' is a viable match.\n", | ||
4955 | escape_essid(network->ssid, network->ssid_len), | ||
4956 | MAC_ARG(network->bssid)); | ||
4957 | |||
4958 | return 1; | ||
4959 | } | ||
4960 | |||
4961 | static void ipw_merge_adhoc_network(void *data) | ||
4962 | { | ||
4963 | struct ipw_priv *priv = data; | ||
4964 | struct ieee80211_network *network = NULL; | ||
4965 | struct ipw_network_match match = { | ||
4966 | .network = priv->assoc_network | ||
4967 | }; | ||
4968 | |||
4969 | if ((priv->status & STATUS_ASSOCIATED) | ||
4970 | && (priv->ieee->iw_mode == IW_MODE_ADHOC)) { | ||
4971 | /* First pass through ROAM process -- look for a better | ||
4972 | * network */ | ||
4973 | unsigned long flags; | ||
4974 | |||
4975 | spin_lock_irqsave(&priv->ieee->lock, flags); | ||
4976 | list_for_each_entry(network, &priv->ieee->network_list, list) { | ||
4977 | if (network != priv->assoc_network) | ||
4978 | ipw_find_adhoc_network(priv, &match, network, | ||
4979 | 1); | ||
4980 | } | ||
4981 | spin_unlock_irqrestore(&priv->ieee->lock, flags); | ||
4982 | |||
4983 | if (match.network == priv->assoc_network) { | ||
4984 | IPW_DEBUG_MERGE("No better ADHOC in this network to " | ||
4985 | "merge to.\n"); | ||
4986 | return; | ||
4987 | } | ||
4988 | |||
4989 | down(&priv->sem); | ||
4990 | if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { | ||
4991 | IPW_DEBUG_MERGE("remove network %s\n", | ||
4992 | escape_essid(priv->essid, | ||
4993 | priv->essid_len)); | ||
4994 | ipw_remove_current_network(priv); | ||
4995 | } | ||
4996 | |||
4997 | ipw_disassociate(priv); | ||
4998 | priv->assoc_network = match.network; | ||
4999 | up(&priv->sem); | ||
5000 | return; | ||
5001 | } | ||
5002 | |||
5003 | } | ||
5004 | |||
4718 | static int ipw_best_network(struct ipw_priv *priv, | 5005 | static int ipw_best_network(struct ipw_priv *priv, |
4719 | struct ipw_network_match *match, | 5006 | struct ipw_network_match *match, |
4720 | struct ieee80211_network *network, int roaming) | 5007 | struct ieee80211_network *network, int roaming) |
@@ -4997,6 +5284,14 @@ static void ipw_adhoc_check(void *data) | |||
4997 | priv->assoc_request.beacon_interval); | 5284 | priv->assoc_request.beacon_interval); |
4998 | } | 5285 | } |
4999 | 5286 | ||
5287 | static void ipw_bg_adhoc_check(void *data) | ||
5288 | { | ||
5289 | struct ipw_priv *priv = data; | ||
5290 | down(&priv->sem); | ||
5291 | ipw_adhoc_check(data); | ||
5292 | up(&priv->sem); | ||
5293 | } | ||
5294 | |||
5000 | #ifdef CONFIG_IPW_DEBUG | 5295 | #ifdef CONFIG_IPW_DEBUG |
5001 | static void ipw_debug_config(struct ipw_priv *priv) | 5296 | static void ipw_debug_config(struct ipw_priv *priv) |
5002 | { | 5297 | { |
@@ -5181,10 +5476,9 @@ static int ipw_request_scan(struct ipw_priv *priv) | |||
5181 | /* If we are roaming, then make this a directed scan for the current | 5476 | /* If we are roaming, then make this a directed scan for the current |
5182 | * network. Otherwise, ensure that every other scan is a fast | 5477 | * network. Otherwise, ensure that every other scan is a fast |
5183 | * channel hop scan */ | 5478 | * channel hop scan */ |
5184 | if ((priv->status & STATUS_ROAMING) | 5479 | if ((priv->status & STATUS_ROAMING) || (!(priv->status & STATUS_ASSOCIATED) && (priv->config & CFG_STATIC_ESSID) && (le32_to_cpu(scan.full_scan_index) % 2))) { /* || ( |
5185 | || (!(priv->status & STATUS_ASSOCIATED) | 5480 | (priv->status & STATUS_ASSOCIATED) && |
5186 | && (priv->config & CFG_STATIC_ESSID) | 5481 | (priv->ieee->iw_mode == IW_MODE_ADHOC))) { */ |
5187 | && (le32_to_cpu(scan.full_scan_index) % 2))) { | ||
5188 | err = ipw_send_ssid(priv, priv->essid, priv->essid_len); | 5482 | err = ipw_send_ssid(priv, priv->essid, priv->essid_len); |
5189 | if (err) { | 5483 | if (err) { |
5190 | IPW_DEBUG_HC | 5484 | IPW_DEBUG_HC |
@@ -5257,6 +5551,22 @@ static int ipw_request_scan(struct ipw_priv *priv) | |||
5257 | return 0; | 5551 | return 0; |
5258 | } | 5552 | } |
5259 | 5553 | ||
5554 | static void ipw_bg_request_scan(void *data) | ||
5555 | { | ||
5556 | struct ipw_priv *priv = data; | ||
5557 | down(&priv->sem); | ||
5558 | ipw_request_scan(data); | ||
5559 | up(&priv->sem); | ||
5560 | } | ||
5561 | |||
5562 | static void ipw_bg_abort_scan(void *data) | ||
5563 | { | ||
5564 | struct ipw_priv *priv = data; | ||
5565 | down(&priv->sem); | ||
5566 | ipw_abort_scan(data); | ||
5567 | up(&priv->sem); | ||
5568 | } | ||
5569 | |||
5260 | /* Support for wpa_supplicant. Will be replaced with WEXT once | 5570 | /* Support for wpa_supplicant. Will be replaced with WEXT once |
5261 | * they get WPA support. */ | 5571 | * they get WPA support. */ |
5262 | 5572 | ||
@@ -5473,8 +5783,7 @@ void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len) | |||
5473 | /* make sure WPA is enabled */ | 5783 | /* make sure WPA is enabled */ |
5474 | ipw_wpa_enable(priv, 1); | 5784 | ipw_wpa_enable(priv, 1); |
5475 | 5785 | ||
5476 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) | 5786 | ipw_disassociate(priv); |
5477 | ipw_disassociate(priv); | ||
5478 | } | 5787 | } |
5479 | 5788 | ||
5480 | static int ipw_wpa_set_wpa_ie(struct net_device *dev, | 5789 | static int ipw_wpa_set_wpa_ie(struct net_device *dev, |
@@ -5830,6 +6139,12 @@ static int ipw_associate_network(struct ipw_priv *priv, | |||
5830 | priv->sys_config.dot11g_auto_detection = 1; | 6139 | priv->sys_config.dot11g_auto_detection = 1; |
5831 | else | 6140 | else |
5832 | priv->sys_config.dot11g_auto_detection = 0; | 6141 | priv->sys_config.dot11g_auto_detection = 0; |
6142 | |||
6143 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) | ||
6144 | priv->sys_config.answer_broadcast_ssid_probe = 1; | ||
6145 | else | ||
6146 | priv->sys_config.answer_broadcast_ssid_probe = 0; | ||
6147 | |||
5833 | err = ipw_send_system_config(priv, &priv->sys_config); | 6148 | err = ipw_send_system_config(priv, &priv->sys_config); |
5834 | if (err) { | 6149 | if (err) { |
5835 | IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); | 6150 | IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); |
@@ -5933,7 +6248,15 @@ static void ipw_roam(void *data) | |||
5933 | priv->status &= ~STATUS_ROAMING; | 6248 | priv->status &= ~STATUS_ROAMING; |
5934 | } | 6249 | } |
5935 | 6250 | ||
5936 | static void ipw_associate(void *data) | 6251 | static void ipw_bg_roam(void *data) |
6252 | { | ||
6253 | struct ipw_priv *priv = data; | ||
6254 | down(&priv->sem); | ||
6255 | ipw_roam(data); | ||
6256 | up(&priv->sem); | ||
6257 | } | ||
6258 | |||
6259 | static int ipw_associate(void *data) | ||
5937 | { | 6260 | { |
5938 | struct ipw_priv *priv = data; | 6261 | struct ipw_priv *priv = data; |
5939 | 6262 | ||
@@ -5945,11 +6268,23 @@ static void ipw_associate(void *data) | |||
5945 | struct list_head *element; | 6268 | struct list_head *element; |
5946 | unsigned long flags; | 6269 | unsigned long flags; |
5947 | 6270 | ||
6271 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | ||
6272 | IPW_DEBUG_ASSOC | ||
6273 | ("Not attempting association (already in progress)\n"); | ||
6274 | return 0; | ||
6275 | } | ||
6276 | |||
6277 | if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) { | ||
6278 | IPW_DEBUG_ASSOC | ||
6279 | ("Not attempting association (scanning or not initialized)\n"); | ||
6280 | return 0; | ||
6281 | } | ||
6282 | |||
5948 | if (!(priv->config & CFG_ASSOCIATE) && | 6283 | if (!(priv->config & CFG_ASSOCIATE) && |
5949 | !(priv->config & (CFG_STATIC_ESSID | | 6284 | !(priv->config & (CFG_STATIC_ESSID | |
5950 | CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) { | 6285 | CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) { |
5951 | IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n"); | 6286 | IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n"); |
5952 | return; | 6287 | return 0; |
5953 | } | 6288 | } |
5954 | 6289 | ||
5955 | /* Protect our use of the network_list */ | 6290 | /* Protect our use of the network_list */ |
@@ -5984,10 +6319,20 @@ static void ipw_associate(void *data) | |||
5984 | queue_delayed_work(priv->workqueue, &priv->request_scan, | 6319 | queue_delayed_work(priv->workqueue, &priv->request_scan, |
5985 | SCAN_INTERVAL); | 6320 | SCAN_INTERVAL); |
5986 | 6321 | ||
5987 | return; | 6322 | return 0; |
5988 | } | 6323 | } |
5989 | 6324 | ||
5990 | ipw_associate_network(priv, network, rates, 0); | 6325 | ipw_associate_network(priv, network, rates, 0); |
6326 | |||
6327 | return 1; | ||
6328 | } | ||
6329 | |||
6330 | static void ipw_bg_associate(void *data) | ||
6331 | { | ||
6332 | struct ipw_priv *priv = data; | ||
6333 | down(&priv->sem); | ||
6334 | ipw_associate(data); | ||
6335 | up(&priv->sem); | ||
5991 | } | 6336 | } |
5992 | 6337 | ||
5993 | static inline void ipw_handle_data_packet(struct ipw_priv *priv, | 6338 | static inline void ipw_handle_data_packet(struct ipw_priv *priv, |
@@ -6037,6 +6382,10 @@ static inline int is_network_packet(struct ipw_priv *priv, | |||
6037 | * this network, discarding packets coming from ourselves */ | 6382 | * this network, discarding packets coming from ourselves */ |
6038 | switch (priv->ieee->iw_mode) { | 6383 | switch (priv->ieee->iw_mode) { |
6039 | case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */ | 6384 | case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */ |
6385 | /* packets from our adapter are dropped (echo) */ | ||
6386 | if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN)) | ||
6387 | return 0; | ||
6388 | |||
6040 | /* {broad,multi}cast packets to our IBSS go through */ | 6389 | /* {broad,multi}cast packets to our IBSS go through */ |
6041 | if (is_broadcast_ether_addr(header->addr1) || | 6390 | if (is_broadcast_ether_addr(header->addr1) || |
6042 | is_multicast_ether_addr(header->addr1)) | 6391 | is_multicast_ether_addr(header->addr1)) |
@@ -6045,9 +6394,12 @@ static inline int is_network_packet(struct ipw_priv *priv, | |||
6045 | /* packets to our adapter go through */ | 6394 | /* packets to our adapter go through */ |
6046 | return !memcmp(header->addr1, priv->net_dev->dev_addr, | 6395 | return !memcmp(header->addr1, priv->net_dev->dev_addr, |
6047 | ETH_ALEN); | 6396 | ETH_ALEN); |
6048 | break; | ||
6049 | 6397 | ||
6050 | case IW_MODE_INFRA: /* Header: Dest. | AP{BSSID} | Source */ | 6398 | case IW_MODE_INFRA: /* Header: Dest. | AP{BSSID} | Source */ |
6399 | /* packets from our adapter are dropped (echo) */ | ||
6400 | if (!memcmp(header->addr3, priv->net_dev->dev_addr, ETH_ALEN)) | ||
6401 | return 0; | ||
6402 | |||
6051 | /* {broad,multi}cast packets to our IBSS go through */ | 6403 | /* {broad,multi}cast packets to our IBSS go through */ |
6052 | if (is_broadcast_ether_addr(header->addr1) || | 6404 | if (is_broadcast_ether_addr(header->addr1) || |
6053 | is_multicast_ether_addr(header->addr1)) | 6405 | is_multicast_ether_addr(header->addr1)) |
@@ -6056,7 +6408,6 @@ static inline int is_network_packet(struct ipw_priv *priv, | |||
6056 | /* packets to our adapter go through */ | 6408 | /* packets to our adapter go through */ |
6057 | return !memcmp(header->addr1, priv->net_dev->dev_addr, | 6409 | return !memcmp(header->addr1, priv->net_dev->dev_addr, |
6058 | ETH_ALEN); | 6410 | ETH_ALEN); |
6059 | break; | ||
6060 | } | 6411 | } |
6061 | 6412 | ||
6062 | return 1; | 6413 | return 1; |
@@ -6101,9 +6452,13 @@ static void ipw_rx(struct ipw_priv *priv) | |||
6101 | switch (pkt->header.message_type) { | 6452 | switch (pkt->header.message_type) { |
6102 | case RX_FRAME_TYPE: /* 802.11 frame */ { | 6453 | case RX_FRAME_TYPE: /* 802.11 frame */ { |
6103 | struct ieee80211_rx_stats stats = { | 6454 | struct ieee80211_rx_stats stats = { |
6104 | .rssi = pkt->u.frame.rssi_dbm - | 6455 | .rssi = |
6456 | le16_to_cpu(pkt->u.frame.rssi_dbm) - | ||
6105 | IPW_RSSI_TO_DBM, | 6457 | IPW_RSSI_TO_DBM, |
6106 | /* .signal = le16_to_cpu(pkt->u.frame.signal), */ | 6458 | .signal = |
6459 | le16_to_cpu(pkt->u.frame.signal), | ||
6460 | .noise = | ||
6461 | le16_to_cpu(pkt->u.frame.noise), | ||
6107 | .rate = pkt->u.frame.rate, | 6462 | .rate = pkt->u.frame.rate, |
6108 | .mac_time = jiffies, | 6463 | .mac_time = jiffies, |
6109 | .received_channel = | 6464 | .received_channel = |
@@ -6120,6 +6475,8 @@ static void ipw_rx(struct ipw_priv *priv) | |||
6120 | stats.mask |= IEEE80211_STATMASK_RSSI; | 6475 | stats.mask |= IEEE80211_STATMASK_RSSI; |
6121 | if (stats.signal != 0) | 6476 | if (stats.signal != 0) |
6122 | stats.mask |= IEEE80211_STATMASK_SIGNAL; | 6477 | stats.mask |= IEEE80211_STATMASK_SIGNAL; |
6478 | if (stats.noise != 0) | ||
6479 | stats.mask |= IEEE80211_STATMASK_NOISE; | ||
6123 | if (stats.rate != 0) | 6480 | if (stats.rate != 0) |
6124 | stats.mask |= IEEE80211_STATMASK_RATE; | 6481 | stats.mask |= IEEE80211_STATMASK_RATE; |
6125 | 6482 | ||
@@ -6179,11 +6536,34 @@ static void ipw_rx(struct ipw_priv *priv) | |||
6179 | || | 6536 | || |
6180 | (WLAN_FC_GET_STYPE | 6537 | (WLAN_FC_GET_STYPE |
6181 | (le16_to_cpu(header->frame_ctl)) | 6538 | (le16_to_cpu(header->frame_ctl)) |
6182 | == IEEE80211_STYPE_BEACON)) | 6539 | == IEEE80211_STYPE_BEACON))) { |
6183 | && !memcmp(header->addr3, | 6540 | if (!memcmp |
6184 | priv->bssid, ETH_ALEN)) | 6541 | (header->addr3, priv->bssid, |
6185 | ipw_add_station(priv, | 6542 | ETH_ALEN)) |
6186 | header->addr2); | 6543 | ipw_add_station(priv, |
6544 | header-> | ||
6545 | addr2); | ||
6546 | else { | ||
6547 | struct | ||
6548 | ieee80211_probe_response | ||
6549 | *beacon; | ||
6550 | beacon = | ||
6551 | (struct | ||
6552 | ieee80211_probe_response | ||
6553 | *)header; | ||
6554 | if (le16_to_cpu | ||
6555 | (beacon-> | ||
6556 | capability) & | ||
6557 | WLAN_CAPABILITY_IBSS) | ||
6558 | { | ||
6559 | queue_work | ||
6560 | (priv-> | ||
6561 | workqueue, | ||
6562 | &priv-> | ||
6563 | merge_networks); | ||
6564 | } | ||
6565 | } | ||
6566 | } | ||
6187 | break; | 6567 | break; |
6188 | 6568 | ||
6189 | case IEEE80211_FTYPE_CTL: | 6569 | case IEEE80211_FTYPE_CTL: |
@@ -6262,14 +6642,16 @@ static int ipw_wx_get_name(struct net_device *dev, | |||
6262 | union iwreq_data *wrqu, char *extra) | 6642 | union iwreq_data *wrqu, char *extra) |
6263 | { | 6643 | { |
6264 | struct ipw_priv *priv = ieee80211_priv(dev); | 6644 | struct ipw_priv *priv = ieee80211_priv(dev); |
6265 | if (priv->status & STATUS_RF_KILL_MASK) { | 6645 | down(&priv->sem); |
6646 | if (priv->status & STATUS_RF_KILL_MASK) | ||
6266 | strcpy(wrqu->name, "radio off"); | 6647 | strcpy(wrqu->name, "radio off"); |
6267 | } else if (!(priv->status & STATUS_ASSOCIATED)) | 6648 | else if (!(priv->status & STATUS_ASSOCIATED)) |
6268 | strcpy(wrqu->name, "unassociated"); | 6649 | strcpy(wrqu->name, "unassociated"); |
6269 | else | 6650 | else |
6270 | snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", | 6651 | snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", |
6271 | ipw_modes[priv->assoc_request.ieee_mode]); | 6652 | ipw_modes[priv->assoc_request.ieee_mode]); |
6272 | IPW_DEBUG_WX("Name: %s\n", wrqu->name); | 6653 | IPW_DEBUG_WX("Name: %s\n", wrqu->name); |
6654 | up(&priv->sem); | ||
6273 | return 0; | 6655 | return 0; |
6274 | } | 6656 | } |
6275 | 6657 | ||
@@ -6278,13 +6660,9 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel) | |||
6278 | if (channel == 0) { | 6660 | if (channel == 0) { |
6279 | IPW_DEBUG_INFO("Setting channel to ANY (0)\n"); | 6661 | IPW_DEBUG_INFO("Setting channel to ANY (0)\n"); |
6280 | priv->config &= ~CFG_STATIC_CHANNEL; | 6662 | priv->config &= ~CFG_STATIC_CHANNEL; |
6281 | if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED | | 6663 | IPW_DEBUG_ASSOC("Attempting to associate with new " |
6282 | STATUS_ASSOCIATING))) { | 6664 | "parameters.\n"); |
6283 | IPW_DEBUG_ASSOC("Attempting to associate with new " | 6665 | ipw_associate(priv); |
6284 | "parameters.\n"); | ||
6285 | ipw_associate(priv); | ||
6286 | } | ||
6287 | |||
6288 | return 0; | 6666 | return 0; |
6289 | } | 6667 | } |
6290 | 6668 | ||
@@ -6299,12 +6677,9 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel) | |||
6299 | IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel); | 6677 | IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel); |
6300 | priv->channel = channel; | 6678 | priv->channel = channel; |
6301 | 6679 | ||
6302 | /* If we are currently associated, or trying to associate | 6680 | /* Network configuration changed -- force [re]association */ |
6303 | * then see if this is a new channel (causing us to disassociate) */ | 6681 | IPW_DEBUG_ASSOC("[re]association triggered due to channel change.\n"); |
6304 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 6682 | if (!ipw_disassociate(priv)) |
6305 | IPW_DEBUG_ASSOC("Disassociating due to channel change.\n"); | ||
6306 | ipw_disassociate(priv); | ||
6307 | } else if (!(priv->status & (STATUS_SCANNING))) | ||
6308 | ipw_associate(priv); | 6683 | ipw_associate(priv); |
6309 | 6684 | ||
6310 | return 0; | 6685 | return 0; |
@@ -6316,6 +6691,7 @@ static int ipw_wx_set_freq(struct net_device *dev, | |||
6316 | { | 6691 | { |
6317 | struct ipw_priv *priv = ieee80211_priv(dev); | 6692 | struct ipw_priv *priv = ieee80211_priv(dev); |
6318 | struct iw_freq *fwrq = &wrqu->freq; | 6693 | struct iw_freq *fwrq = &wrqu->freq; |
6694 | int ret = 0; | ||
6319 | 6695 | ||
6320 | /* if setting by freq convert to channel */ | 6696 | /* if setting by freq convert to channel */ |
6321 | if (fwrq->e == 1) { | 6697 | if (fwrq->e == 1) { |
@@ -6337,7 +6713,10 @@ static int ipw_wx_set_freq(struct net_device *dev, | |||
6337 | return -EOPNOTSUPP; | 6713 | return -EOPNOTSUPP; |
6338 | 6714 | ||
6339 | IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); | 6715 | IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); |
6340 | return ipw_set_channel(priv, (u8) fwrq->m); | 6716 | down(&priv->sem); |
6717 | ret = ipw_set_channel(priv, (u8) fwrq->m); | ||
6718 | up(&priv->sem); | ||
6719 | return ret; | ||
6341 | } | 6720 | } |
6342 | 6721 | ||
6343 | static int ipw_wx_get_freq(struct net_device *dev, | 6722 | static int ipw_wx_get_freq(struct net_device *dev, |
@@ -6350,12 +6729,14 @@ static int ipw_wx_get_freq(struct net_device *dev, | |||
6350 | 6729 | ||
6351 | /* If we are associated, trying to associate, or have a statically | 6730 | /* If we are associated, trying to associate, or have a statically |
6352 | * configured CHANNEL then return that; otherwise return ANY */ | 6731 | * configured CHANNEL then return that; otherwise return ANY */ |
6732 | down(&priv->sem); | ||
6353 | if (priv->config & CFG_STATIC_CHANNEL || | 6733 | if (priv->config & CFG_STATIC_CHANNEL || |
6354 | priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) | 6734 | priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) |
6355 | wrqu->freq.m = priv->channel; | 6735 | wrqu->freq.m = priv->channel; |
6356 | else | 6736 | else |
6357 | wrqu->freq.m = 0; | 6737 | wrqu->freq.m = 0; |
6358 | 6738 | ||
6739 | up(&priv->sem); | ||
6359 | IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); | 6740 | IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); |
6360 | return 0; | 6741 | return 0; |
6361 | } | 6742 | } |
@@ -6368,9 +6749,11 @@ static int ipw_wx_set_mode(struct net_device *dev, | |||
6368 | int err = 0; | 6749 | int err = 0; |
6369 | 6750 | ||
6370 | IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode); | 6751 | IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode); |
6371 | 6752 | down(&priv->sem); | |
6372 | if (wrqu->mode == priv->ieee->iw_mode) | 6753 | if (wrqu->mode == priv->ieee->iw_mode) { |
6754 | up(&priv->sem); | ||
6373 | return 0; | 6755 | return 0; |
6756 | } | ||
6374 | 6757 | ||
6375 | switch (wrqu->mode) { | 6758 | switch (wrqu->mode) { |
6376 | #ifdef CONFIG_IPW_MONITOR | 6759 | #ifdef CONFIG_IPW_MONITOR |
@@ -6383,6 +6766,7 @@ static int ipw_wx_set_mode(struct net_device *dev, | |||
6383 | wrqu->mode = IW_MODE_INFRA; | 6766 | wrqu->mode = IW_MODE_INFRA; |
6384 | break; | 6767 | break; |
6385 | default: | 6768 | default: |
6769 | up(&priv->sem); | ||
6386 | return -EINVAL; | 6770 | return -EINVAL; |
6387 | } | 6771 | } |
6388 | 6772 | ||
@@ -6407,8 +6791,9 @@ static int ipw_wx_set_mode(struct net_device *dev, | |||
6407 | #endif | 6791 | #endif |
6408 | 6792 | ||
6409 | priv->ieee->iw_mode = wrqu->mode; | 6793 | priv->ieee->iw_mode = wrqu->mode; |
6410 | queue_work(priv->workqueue, &priv->adapter_restart); | ||
6411 | 6794 | ||
6795 | queue_work(priv->workqueue, &priv->adapter_restart); | ||
6796 | up(&priv->sem); | ||
6412 | return err; | 6797 | return err; |
6413 | } | 6798 | } |
6414 | 6799 | ||
@@ -6417,10 +6802,10 @@ static int ipw_wx_get_mode(struct net_device *dev, | |||
6417 | union iwreq_data *wrqu, char *extra) | 6802 | union iwreq_data *wrqu, char *extra) |
6418 | { | 6803 | { |
6419 | struct ipw_priv *priv = ieee80211_priv(dev); | 6804 | struct ipw_priv *priv = ieee80211_priv(dev); |
6420 | 6805 | down(&priv->sem); | |
6421 | wrqu->mode = priv->ieee->iw_mode; | 6806 | wrqu->mode = priv->ieee->iw_mode; |
6422 | IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode); | 6807 | IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode); |
6423 | 6808 | up(&priv->sem); | |
6424 | return 0; | 6809 | return 0; |
6425 | } | 6810 | } |
6426 | 6811 | ||
@@ -6466,7 +6851,7 @@ static int ipw_wx_get_range(struct net_device *dev, | |||
6466 | range->max_qual.qual = 100; | 6851 | range->max_qual.qual = 100; |
6467 | /* TODO: Find real max RSSI and stick here */ | 6852 | /* TODO: Find real max RSSI and stick here */ |
6468 | range->max_qual.level = 0; | 6853 | range->max_qual.level = 0; |
6469 | range->max_qual.noise = 0; | 6854 | range->max_qual.noise = priv->ieee->worst_rssi + 0x100; |
6470 | range->max_qual.updated = 7; /* Updated all three */ | 6855 | range->max_qual.updated = 7; /* Updated all three */ |
6471 | 6856 | ||
6472 | range->avg_qual.qual = 70; | 6857 | range->avg_qual.qual = 70; |
@@ -6474,7 +6859,7 @@ static int ipw_wx_get_range(struct net_device *dev, | |||
6474 | range->avg_qual.level = 0; /* FIXME to real average level */ | 6859 | range->avg_qual.level = 0; /* FIXME to real average level */ |
6475 | range->avg_qual.noise = 0; | 6860 | range->avg_qual.noise = 0; |
6476 | range->avg_qual.updated = 7; /* Updated all three */ | 6861 | range->avg_qual.updated = 7; /* Updated all three */ |
6477 | 6862 | down(&priv->sem); | |
6478 | range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES); | 6863 | range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES); |
6479 | 6864 | ||
6480 | for (i = 0; i < range->num_bitrates; i++) | 6865 | for (i = 0; i < range->num_bitrates; i++) |
@@ -6507,7 +6892,7 @@ static int ipw_wx_get_range(struct net_device *dev, | |||
6507 | break; | 6892 | break; |
6508 | } | 6893 | } |
6509 | range->num_frequency = val; | 6894 | range->num_frequency = val; |
6510 | 6895 | up(&priv->sem); | |
6511 | IPW_DEBUG_WX("GET Range\n"); | 6896 | IPW_DEBUG_WX("GET Range\n"); |
6512 | return 0; | 6897 | return 0; |
6513 | } | 6898 | } |
@@ -6527,25 +6912,23 @@ static int ipw_wx_set_wap(struct net_device *dev, | |||
6527 | 6912 | ||
6528 | if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) | 6913 | if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) |
6529 | return -EINVAL; | 6914 | return -EINVAL; |
6530 | 6915 | down(&priv->sem); | |
6531 | if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || | 6916 | if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || |
6532 | !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { | 6917 | !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { |
6533 | /* we disable mandatory BSSID association */ | 6918 | /* we disable mandatory BSSID association */ |
6534 | IPW_DEBUG_WX("Setting AP BSSID to ANY\n"); | 6919 | IPW_DEBUG_WX("Setting AP BSSID to ANY\n"); |
6535 | priv->config &= ~CFG_STATIC_BSSID; | 6920 | priv->config &= ~CFG_STATIC_BSSID; |
6536 | if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED | | 6921 | IPW_DEBUG_ASSOC("Attempting to associate with new " |
6537 | STATUS_ASSOCIATING))) { | 6922 | "parameters.\n"); |
6538 | IPW_DEBUG_ASSOC("Attempting to associate with new " | 6923 | ipw_associate(priv); |
6539 | "parameters.\n"); | 6924 | up(&priv->sem); |
6540 | ipw_associate(priv); | ||
6541 | } | ||
6542 | |||
6543 | return 0; | 6925 | return 0; |
6544 | } | 6926 | } |
6545 | 6927 | ||
6546 | priv->config |= CFG_STATIC_BSSID; | 6928 | priv->config |= CFG_STATIC_BSSID; |
6547 | if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) { | 6929 | if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) { |
6548 | IPW_DEBUG_WX("BSSID set to current BSSID.\n"); | 6930 | IPW_DEBUG_WX("BSSID set to current BSSID.\n"); |
6931 | up(&priv->sem); | ||
6549 | return 0; | 6932 | return 0; |
6550 | } | 6933 | } |
6551 | 6934 | ||
@@ -6554,14 +6937,12 @@ static int ipw_wx_set_wap(struct net_device *dev, | |||
6554 | 6937 | ||
6555 | memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); | 6938 | memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); |
6556 | 6939 | ||
6557 | /* If we are currently associated, or trying to associate | 6940 | /* Network configuration changed -- force [re]association */ |
6558 | * then see if this is a new BSSID (causing us to disassociate) */ | 6941 | IPW_DEBUG_ASSOC("[re]association triggered due to BSSID change.\n"); |
6559 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 6942 | if (!ipw_disassociate(priv)) |
6560 | IPW_DEBUG_ASSOC("Disassociating due to BSSID change.\n"); | ||
6561 | ipw_disassociate(priv); | ||
6562 | } else if (!(priv->status & (STATUS_SCANNING))) | ||
6563 | ipw_associate(priv); | 6943 | ipw_associate(priv); |
6564 | 6944 | ||
6945 | up(&priv->sem); | ||
6565 | return 0; | 6946 | return 0; |
6566 | } | 6947 | } |
6567 | 6948 | ||
@@ -6572,6 +6953,7 @@ static int ipw_wx_get_wap(struct net_device *dev, | |||
6572 | struct ipw_priv *priv = ieee80211_priv(dev); | 6953 | struct ipw_priv *priv = ieee80211_priv(dev); |
6573 | /* If we are associated, trying to associate, or have a statically | 6954 | /* If we are associated, trying to associate, or have a statically |
6574 | * configured BSSID then return that; otherwise return ANY */ | 6955 | * configured BSSID then return that; otherwise return ANY */ |
6956 | down(&priv->sem); | ||
6575 | if (priv->config & CFG_STATIC_BSSID || | 6957 | if (priv->config & CFG_STATIC_BSSID || |
6576 | priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 6958 | priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { |
6577 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; | 6959 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; |
@@ -6581,6 +6963,7 @@ static int ipw_wx_get_wap(struct net_device *dev, | |||
6581 | 6963 | ||
6582 | IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", | 6964 | IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", |
6583 | MAC_ARG(wrqu->ap_addr.sa_data)); | 6965 | MAC_ARG(wrqu->ap_addr.sa_data)); |
6966 | up(&priv->sem); | ||
6584 | return 0; | 6967 | return 0; |
6585 | } | 6968 | } |
6586 | 6969 | ||
@@ -6591,7 +6974,7 @@ static int ipw_wx_set_essid(struct net_device *dev, | |||
6591 | struct ipw_priv *priv = ieee80211_priv(dev); | 6974 | struct ipw_priv *priv = ieee80211_priv(dev); |
6592 | char *essid = ""; /* ANY */ | 6975 | char *essid = ""; /* ANY */ |
6593 | int length = 0; | 6976 | int length = 0; |
6594 | 6977 | down(&priv->sem); | |
6595 | if (wrqu->essid.flags && wrqu->essid.length) { | 6978 | if (wrqu->essid.flags && wrqu->essid.length) { |
6596 | length = wrqu->essid.length - 1; | 6979 | length = wrqu->essid.length - 1; |
6597 | essid = extra; | 6980 | essid = extra; |
@@ -6599,13 +6982,12 @@ static int ipw_wx_set_essid(struct net_device *dev, | |||
6599 | if (length == 0) { | 6982 | if (length == 0) { |
6600 | IPW_DEBUG_WX("Setting ESSID to ANY\n"); | 6983 | IPW_DEBUG_WX("Setting ESSID to ANY\n"); |
6601 | priv->config &= ~CFG_STATIC_ESSID; | 6984 | priv->config &= ~CFG_STATIC_ESSID; |
6602 | if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED | | 6985 | if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { |
6603 | STATUS_ASSOCIATING))) { | ||
6604 | IPW_DEBUG_ASSOC("Attempting to associate with new " | 6986 | IPW_DEBUG_ASSOC("Attempting to associate with new " |
6605 | "parameters.\n"); | 6987 | "parameters.\n"); |
6606 | ipw_associate(priv); | 6988 | ipw_associate(priv); |
6607 | } | 6989 | } |
6608 | 6990 | up(&priv->sem); | |
6609 | return 0; | 6991 | return 0; |
6610 | } | 6992 | } |
6611 | 6993 | ||
@@ -6615,6 +6997,7 @@ static int ipw_wx_set_essid(struct net_device *dev, | |||
6615 | 6997 | ||
6616 | if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) { | 6998 | if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) { |
6617 | IPW_DEBUG_WX("ESSID set to current ESSID.\n"); | 6999 | IPW_DEBUG_WX("ESSID set to current ESSID.\n"); |
7000 | up(&priv->sem); | ||
6618 | return 0; | 7001 | return 0; |
6619 | } | 7002 | } |
6620 | 7003 | ||
@@ -6624,14 +7007,12 @@ static int ipw_wx_set_essid(struct net_device *dev, | |||
6624 | priv->essid_len = length; | 7007 | priv->essid_len = length; |
6625 | memcpy(priv->essid, essid, priv->essid_len); | 7008 | memcpy(priv->essid, essid, priv->essid_len); |
6626 | 7009 | ||
6627 | /* If we are currently associated, or trying to associate | 7010 | /* Network configuration changed -- force [re]association */ |
6628 | * then see if this is a new ESSID (causing us to disassociate) */ | 7011 | IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n"); |
6629 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 7012 | if (!ipw_disassociate(priv)) |
6630 | IPW_DEBUG_ASSOC("Disassociating due to ESSID change.\n"); | ||
6631 | ipw_disassociate(priv); | ||
6632 | } else if (!(priv->status & (STATUS_SCANNING))) | ||
6633 | ipw_associate(priv); | 7013 | ipw_associate(priv); |
6634 | 7014 | ||
7015 | up(&priv->sem); | ||
6635 | return 0; | 7016 | return 0; |
6636 | } | 7017 | } |
6637 | 7018 | ||
@@ -6643,6 +7024,7 @@ static int ipw_wx_get_essid(struct net_device *dev, | |||
6643 | 7024 | ||
6644 | /* If we are associated, trying to associate, or have a statically | 7025 | /* If we are associated, trying to associate, or have a statically |
6645 | * configured ESSID then return that; otherwise return ANY */ | 7026 | * configured ESSID then return that; otherwise return ANY */ |
7027 | down(&priv->sem); | ||
6646 | if (priv->config & CFG_STATIC_ESSID || | 7028 | if (priv->config & CFG_STATIC_ESSID || |
6647 | priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 7029 | priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { |
6648 | IPW_DEBUG_WX("Getting essid: '%s'\n", | 7030 | IPW_DEBUG_WX("Getting essid: '%s'\n", |
@@ -6655,7 +7037,7 @@ static int ipw_wx_get_essid(struct net_device *dev, | |||
6655 | wrqu->essid.length = 0; | 7037 | wrqu->essid.length = 0; |
6656 | wrqu->essid.flags = 0; /* active */ | 7038 | wrqu->essid.flags = 0; /* active */ |
6657 | } | 7039 | } |
6658 | 7040 | up(&priv->sem); | |
6659 | return 0; | 7041 | return 0; |
6660 | } | 7042 | } |
6661 | 7043 | ||
@@ -6668,11 +7050,12 @@ static int ipw_wx_set_nick(struct net_device *dev, | |||
6668 | IPW_DEBUG_WX("Setting nick to '%s'\n", extra); | 7050 | IPW_DEBUG_WX("Setting nick to '%s'\n", extra); |
6669 | if (wrqu->data.length > IW_ESSID_MAX_SIZE) | 7051 | if (wrqu->data.length > IW_ESSID_MAX_SIZE) |
6670 | return -E2BIG; | 7052 | return -E2BIG; |
6671 | 7053 | down(&priv->sem); | |
6672 | wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); | 7054 | wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); |
6673 | memset(priv->nick, 0, sizeof(priv->nick)); | 7055 | memset(priv->nick, 0, sizeof(priv->nick)); |
6674 | memcpy(priv->nick, extra, wrqu->data.length); | 7056 | memcpy(priv->nick, extra, wrqu->data.length); |
6675 | IPW_DEBUG_TRACE("<<\n"); | 7057 | IPW_DEBUG_TRACE("<<\n"); |
7058 | up(&priv->sem); | ||
6676 | return 0; | 7059 | return 0; |
6677 | 7060 | ||
6678 | } | 7061 | } |
@@ -6683,9 +7066,11 @@ static int ipw_wx_get_nick(struct net_device *dev, | |||
6683 | { | 7066 | { |
6684 | struct ipw_priv *priv = ieee80211_priv(dev); | 7067 | struct ipw_priv *priv = ieee80211_priv(dev); |
6685 | IPW_DEBUG_WX("Getting nick\n"); | 7068 | IPW_DEBUG_WX("Getting nick\n"); |
7069 | down(&priv->sem); | ||
6686 | wrqu->data.length = strlen(priv->nick) + 1; | 7070 | wrqu->data.length = strlen(priv->nick) + 1; |
6687 | memcpy(extra, priv->nick, wrqu->data.length); | 7071 | memcpy(extra, priv->nick, wrqu->data.length); |
6688 | wrqu->data.flags = 1; /* active */ | 7072 | wrqu->data.flags = 1; /* active */ |
7073 | up(&priv->sem); | ||
6689 | return 0; | 7074 | return 0; |
6690 | } | 7075 | } |
6691 | 7076 | ||
@@ -6778,25 +7163,26 @@ static int ipw_wx_set_rate(struct net_device *dev, | |||
6778 | apply: | 7163 | apply: |
6779 | IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", | 7164 | IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", |
6780 | mask, fixed ? "fixed" : "sub-rates"); | 7165 | mask, fixed ? "fixed" : "sub-rates"); |
6781 | 7166 | down(&priv->sem); | |
6782 | if (mask == IEEE80211_DEFAULT_RATES_MASK) | 7167 | if (mask == IEEE80211_DEFAULT_RATES_MASK) |
6783 | priv->config &= ~CFG_FIXED_RATE; | 7168 | priv->config &= ~CFG_FIXED_RATE; |
6784 | else | 7169 | else |
6785 | priv->config |= CFG_FIXED_RATE; | 7170 | priv->config |= CFG_FIXED_RATE; |
6786 | 7171 | ||
6787 | if (priv->rates_mask != mask) { | 7172 | if (priv->rates_mask == mask) { |
6788 | priv->rates_mask = mask; | 7173 | IPW_DEBUG_WX("Mask set to current mask.\n"); |
6789 | /* If we are already associated or are currently trying to | 7174 | up(&priv->sem); |
6790 | * associate, disassociate and try again */ | 7175 | return 0; |
6791 | if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { | ||
6792 | IPW_DEBUG_ASSOC("Disassociating due to RATE change.\n"); | ||
6793 | ipw_disassociate(priv); | ||
6794 | } else if (!(priv->status & (STATUS_SCANNING))) { | ||
6795 | /* We are not yet associated, so kick one off... */ | ||
6796 | ipw_associate(priv); | ||
6797 | } | ||
6798 | } | 7176 | } |
6799 | 7177 | ||
7178 | priv->rates_mask = mask; | ||
7179 | |||
7180 | /* Network configuration changed -- force [re]association */ | ||
7181 | IPW_DEBUG_ASSOC("[re]association triggered due to rates change.\n"); | ||
7182 | if (!ipw_disassociate(priv)) | ||
7183 | ipw_associate(priv); | ||
7184 | |||
7185 | up(&priv->sem); | ||
6800 | return 0; | 7186 | return 0; |
6801 | } | 7187 | } |
6802 | 7188 | ||
@@ -6805,8 +7191,9 @@ static int ipw_wx_get_rate(struct net_device *dev, | |||
6805 | union iwreq_data *wrqu, char *extra) | 7191 | union iwreq_data *wrqu, char *extra) |
6806 | { | 7192 | { |
6807 | struct ipw_priv *priv = ieee80211_priv(dev); | 7193 | struct ipw_priv *priv = ieee80211_priv(dev); |
7194 | down(&priv->sem); | ||
6808 | wrqu->bitrate.value = priv->last_rate; | 7195 | wrqu->bitrate.value = priv->last_rate; |
6809 | 7196 | up(&priv->sem); | |
6810 | IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); | 7197 | IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); |
6811 | return 0; | 7198 | return 0; |
6812 | } | 7199 | } |
@@ -6816,18 +7203,20 @@ static int ipw_wx_set_rts(struct net_device *dev, | |||
6816 | union iwreq_data *wrqu, char *extra) | 7203 | union iwreq_data *wrqu, char *extra) |
6817 | { | 7204 | { |
6818 | struct ipw_priv *priv = ieee80211_priv(dev); | 7205 | struct ipw_priv *priv = ieee80211_priv(dev); |
6819 | 7206 | down(&priv->sem); | |
6820 | if (wrqu->rts.disabled) | 7207 | if (wrqu->rts.disabled) |
6821 | priv->rts_threshold = DEFAULT_RTS_THRESHOLD; | 7208 | priv->rts_threshold = DEFAULT_RTS_THRESHOLD; |
6822 | else { | 7209 | else { |
6823 | if (wrqu->rts.value < MIN_RTS_THRESHOLD || | 7210 | if (wrqu->rts.value < MIN_RTS_THRESHOLD || |
6824 | wrqu->rts.value > MAX_RTS_THRESHOLD) | 7211 | wrqu->rts.value > MAX_RTS_THRESHOLD) { |
7212 | up(&priv->sem); | ||
6825 | return -EINVAL; | 7213 | return -EINVAL; |
6826 | 7214 | } | |
6827 | priv->rts_threshold = wrqu->rts.value; | 7215 | priv->rts_threshold = wrqu->rts.value; |
6828 | } | 7216 | } |
6829 | 7217 | ||
6830 | ipw_send_rts_threshold(priv, priv->rts_threshold); | 7218 | ipw_send_rts_threshold(priv, priv->rts_threshold); |
7219 | up(&priv->sem); | ||
6831 | IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold); | 7220 | IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold); |
6832 | return 0; | 7221 | return 0; |
6833 | } | 7222 | } |
@@ -6837,10 +7226,11 @@ static int ipw_wx_get_rts(struct net_device *dev, | |||
6837 | union iwreq_data *wrqu, char *extra) | 7226 | union iwreq_data *wrqu, char *extra) |
6838 | { | 7227 | { |
6839 | struct ipw_priv *priv = ieee80211_priv(dev); | 7228 | struct ipw_priv *priv = ieee80211_priv(dev); |
7229 | down(&priv->sem); | ||
6840 | wrqu->rts.value = priv->rts_threshold; | 7230 | wrqu->rts.value = priv->rts_threshold; |
6841 | wrqu->rts.fixed = 0; /* no auto select */ | 7231 | wrqu->rts.fixed = 0; /* no auto select */ |
6842 | wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); | 7232 | wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); |
6843 | 7233 | up(&priv->sem); | |
6844 | IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value); | 7234 | IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value); |
6845 | return 0; | 7235 | return 0; |
6846 | } | 7236 | } |
@@ -6852,15 +7242,21 @@ static int ipw_wx_set_txpow(struct net_device *dev, | |||
6852 | struct ipw_priv *priv = ieee80211_priv(dev); | 7242 | struct ipw_priv *priv = ieee80211_priv(dev); |
6853 | struct ipw_tx_power tx_power; | 7243 | struct ipw_tx_power tx_power; |
6854 | int i; | 7244 | int i; |
6855 | 7245 | down(&priv->sem); | |
6856 | if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) | 7246 | if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) { |
7247 | up(&priv->sem); | ||
6857 | return -EINPROGRESS; | 7248 | return -EINPROGRESS; |
7249 | } | ||
6858 | 7250 | ||
6859 | if (wrqu->power.flags != IW_TXPOW_DBM) | 7251 | if (wrqu->power.flags != IW_TXPOW_DBM) { |
7252 | up(&priv->sem); | ||
6860 | return -EINVAL; | 7253 | return -EINVAL; |
7254 | } | ||
6861 | 7255 | ||
6862 | if ((wrqu->power.value > 20) || (wrqu->power.value < -12)) | 7256 | if ((wrqu->power.value > 20) || (wrqu->power.value < -12)) { |
7257 | up(&priv->sem); | ||
6863 | return -EINVAL; | 7258 | return -EINVAL; |
7259 | } | ||
6864 | 7260 | ||
6865 | priv->tx_power = wrqu->power.value; | 7261 | priv->tx_power = wrqu->power.value; |
6866 | 7262 | ||
@@ -6881,9 +7277,11 @@ static int ipw_wx_set_txpow(struct net_device *dev, | |||
6881 | if (ipw_send_tx_power(priv, &tx_power)) | 7277 | if (ipw_send_tx_power(priv, &tx_power)) |
6882 | goto error; | 7278 | goto error; |
6883 | 7279 | ||
7280 | up(&priv->sem); | ||
6884 | return 0; | 7281 | return 0; |
6885 | 7282 | ||
6886 | error: | 7283 | error: |
7284 | up(&priv->sem); | ||
6887 | return -EIO; | 7285 | return -EIO; |
6888 | } | 7286 | } |
6889 | 7287 | ||
@@ -6892,11 +7290,12 @@ static int ipw_wx_get_txpow(struct net_device *dev, | |||
6892 | union iwreq_data *wrqu, char *extra) | 7290 | union iwreq_data *wrqu, char *extra) |
6893 | { | 7291 | { |
6894 | struct ipw_priv *priv = ieee80211_priv(dev); | 7292 | struct ipw_priv *priv = ieee80211_priv(dev); |
6895 | 7293 | down(&priv->sem); | |
6896 | wrqu->power.value = priv->tx_power; | 7294 | wrqu->power.value = priv->tx_power; |
6897 | wrqu->power.fixed = 1; | 7295 | wrqu->power.fixed = 1; |
6898 | wrqu->power.flags = IW_TXPOW_DBM; | 7296 | wrqu->power.flags = IW_TXPOW_DBM; |
6899 | wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; | 7297 | wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; |
7298 | up(&priv->sem); | ||
6900 | 7299 | ||
6901 | IPW_DEBUG_WX("GET TX Power -> %s %d \n", | 7300 | IPW_DEBUG_WX("GET TX Power -> %s %d \n", |
6902 | wrqu->power.disabled ? "ON" : "OFF", wrqu->power.value); | 7301 | wrqu->power.disabled ? "ON" : "OFF", wrqu->power.value); |
@@ -6909,7 +7308,7 @@ static int ipw_wx_set_frag(struct net_device *dev, | |||
6909 | union iwreq_data *wrqu, char *extra) | 7308 | union iwreq_data *wrqu, char *extra) |
6910 | { | 7309 | { |
6911 | struct ipw_priv *priv = ieee80211_priv(dev); | 7310 | struct ipw_priv *priv = ieee80211_priv(dev); |
6912 | 7311 | down(&priv->sem); | |
6913 | if (wrqu->frag.disabled) | 7312 | if (wrqu->frag.disabled) |
6914 | priv->ieee->fts = DEFAULT_FTS; | 7313 | priv->ieee->fts = DEFAULT_FTS; |
6915 | else { | 7314 | else { |
@@ -6921,6 +7320,7 @@ static int ipw_wx_set_frag(struct net_device *dev, | |||
6921 | } | 7320 | } |
6922 | 7321 | ||
6923 | ipw_send_frag_threshold(priv, wrqu->frag.value); | 7322 | ipw_send_frag_threshold(priv, wrqu->frag.value); |
7323 | up(&priv->sem); | ||
6924 | IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value); | 7324 | IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value); |
6925 | return 0; | 7325 | return 0; |
6926 | } | 7326 | } |
@@ -6930,10 +7330,11 @@ static int ipw_wx_get_frag(struct net_device *dev, | |||
6930 | union iwreq_data *wrqu, char *extra) | 7330 | union iwreq_data *wrqu, char *extra) |
6931 | { | 7331 | { |
6932 | struct ipw_priv *priv = ieee80211_priv(dev); | 7332 | struct ipw_priv *priv = ieee80211_priv(dev); |
7333 | down(&priv->sem); | ||
6933 | wrqu->frag.value = priv->ieee->fts; | 7334 | wrqu->frag.value = priv->ieee->fts; |
6934 | wrqu->frag.fixed = 0; /* no auto select */ | 7335 | wrqu->frag.fixed = 0; /* no auto select */ |
6935 | wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS); | 7336 | wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS); |
6936 | 7337 | up(&priv->sem); | |
6937 | IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); | 7338 | IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); |
6938 | 7339 | ||
6939 | return 0; | 7340 | return 0; |
@@ -6961,8 +7362,12 @@ static int ipw_wx_set_scan(struct net_device *dev, | |||
6961 | { | 7362 | { |
6962 | struct ipw_priv *priv = ieee80211_priv(dev); | 7363 | struct ipw_priv *priv = ieee80211_priv(dev); |
6963 | IPW_DEBUG_WX("Start scan\n"); | 7364 | IPW_DEBUG_WX("Start scan\n"); |
6964 | if (ipw_request_scan(priv)) | 7365 | down(&priv->sem); |
7366 | if (ipw_request_scan(priv)) { | ||
7367 | up(&priv->sem); | ||
6965 | return -EIO; | 7368 | return -EIO; |
7369 | } | ||
7370 | up(&priv->sem); | ||
6966 | return 0; | 7371 | return 0; |
6967 | } | 7372 | } |
6968 | 7373 | ||
@@ -6996,16 +7401,17 @@ static int ipw_wx_set_power(struct net_device *dev, | |||
6996 | { | 7401 | { |
6997 | struct ipw_priv *priv = ieee80211_priv(dev); | 7402 | struct ipw_priv *priv = ieee80211_priv(dev); |
6998 | int err; | 7403 | int err; |
6999 | 7404 | down(&priv->sem); | |
7000 | if (wrqu->power.disabled) { | 7405 | if (wrqu->power.disabled) { |
7001 | priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); | 7406 | priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); |
7002 | err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM); | 7407 | err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM); |
7003 | if (err) { | 7408 | if (err) { |
7004 | IPW_DEBUG_WX("failed setting power mode.\n"); | 7409 | IPW_DEBUG_WX("failed setting power mode.\n"); |
7410 | up(&priv->sem); | ||
7005 | return err; | 7411 | return err; |
7006 | } | 7412 | } |
7007 | IPW_DEBUG_WX("SET Power Management Mode -> off\n"); | 7413 | IPW_DEBUG_WX("SET Power Management Mode -> off\n"); |
7008 | 7414 | up(&priv->sem); | |
7009 | return 0; | 7415 | return 0; |
7010 | } | 7416 | } |
7011 | 7417 | ||
@@ -7017,6 +7423,7 @@ static int ipw_wx_set_power(struct net_device *dev, | |||
7017 | default: /* Otherwise we don't support it */ | 7423 | default: /* Otherwise we don't support it */ |
7018 | IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", | 7424 | IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", |
7019 | wrqu->power.flags); | 7425 | wrqu->power.flags); |
7426 | up(&priv->sem); | ||
7020 | return -EOPNOTSUPP; | 7427 | return -EOPNOTSUPP; |
7021 | } | 7428 | } |
7022 | 7429 | ||
@@ -7029,11 +7436,12 @@ static int ipw_wx_set_power(struct net_device *dev, | |||
7029 | err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); | 7436 | err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); |
7030 | if (err) { | 7437 | if (err) { |
7031 | IPW_DEBUG_WX("failed setting power mode.\n"); | 7438 | IPW_DEBUG_WX("failed setting power mode.\n"); |
7439 | up(&priv->sem); | ||
7032 | return err; | 7440 | return err; |
7033 | } | 7441 | } |
7034 | 7442 | ||
7035 | IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); | 7443 | IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); |
7036 | 7444 | up(&priv->sem); | |
7037 | return 0; | 7445 | return 0; |
7038 | } | 7446 | } |
7039 | 7447 | ||
@@ -7042,12 +7450,13 @@ static int ipw_wx_get_power(struct net_device *dev, | |||
7042 | union iwreq_data *wrqu, char *extra) | 7450 | union iwreq_data *wrqu, char *extra) |
7043 | { | 7451 | { |
7044 | struct ipw_priv *priv = ieee80211_priv(dev); | 7452 | struct ipw_priv *priv = ieee80211_priv(dev); |
7045 | 7453 | down(&priv->sem); | |
7046 | if (!(priv->power_mode & IPW_POWER_ENABLED)) | 7454 | if (!(priv->power_mode & IPW_POWER_ENABLED)) |
7047 | wrqu->power.disabled = 1; | 7455 | wrqu->power.disabled = 1; |
7048 | else | 7456 | else |
7049 | wrqu->power.disabled = 0; | 7457 | wrqu->power.disabled = 0; |
7050 | 7458 | ||
7459 | up(&priv->sem); | ||
7051 | IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); | 7460 | IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); |
7052 | 7461 | ||
7053 | return 0; | 7462 | return 0; |
@@ -7060,7 +7469,7 @@ static int ipw_wx_set_powermode(struct net_device *dev, | |||
7060 | struct ipw_priv *priv = ieee80211_priv(dev); | 7469 | struct ipw_priv *priv = ieee80211_priv(dev); |
7061 | int mode = *(int *)extra; | 7470 | int mode = *(int *)extra; |
7062 | int err; | 7471 | int err; |
7063 | 7472 | down(&priv->sem); | |
7064 | if ((mode < 1) || (mode > IPW_POWER_LIMIT)) { | 7473 | if ((mode < 1) || (mode > IPW_POWER_LIMIT)) { |
7065 | mode = IPW_POWER_AC; | 7474 | mode = IPW_POWER_AC; |
7066 | priv->power_mode = mode; | 7475 | priv->power_mode = mode; |
@@ -7073,10 +7482,11 @@ static int ipw_wx_set_powermode(struct net_device *dev, | |||
7073 | 7482 | ||
7074 | if (err) { | 7483 | if (err) { |
7075 | IPW_DEBUG_WX("failed setting power mode.\n"); | 7484 | IPW_DEBUG_WX("failed setting power mode.\n"); |
7485 | up(&priv->sem); | ||
7076 | return err; | 7486 | return err; |
7077 | } | 7487 | } |
7078 | } | 7488 | } |
7079 | 7489 | up(&priv->sem); | |
7080 | return 0; | 7490 | return 0; |
7081 | } | 7491 | } |
7082 | 7492 | ||
@@ -7125,7 +7535,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, | |||
7125 | IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode); | 7535 | IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode); |
7126 | return -EINVAL; | 7536 | return -EINVAL; |
7127 | } | 7537 | } |
7128 | 7538 | down(&priv->sem); | |
7129 | if (priv->adapter == IPW_2915ABG) { | 7539 | if (priv->adapter == IPW_2915ABG) { |
7130 | priv->ieee->abg_true = 1; | 7540 | priv->ieee->abg_true = 1; |
7131 | if (mode & IEEE_A) { | 7541 | if (mode & IEEE_A) { |
@@ -7137,6 +7547,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, | |||
7137 | if (mode & IEEE_A) { | 7547 | if (mode & IEEE_A) { |
7138 | IPW_WARNING("Attempt to set 2200BG into " | 7548 | IPW_WARNING("Attempt to set 2200BG into " |
7139 | "802.11a mode\n"); | 7549 | "802.11a mode\n"); |
7550 | up(&priv->sem); | ||
7140 | return -EINVAL; | 7551 | return -EINVAL; |
7141 | } | 7552 | } |
7142 | 7553 | ||
@@ -7160,16 +7571,12 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, | |||
7160 | priv->ieee->modulation = modulation; | 7571 | priv->ieee->modulation = modulation; |
7161 | init_supported_rates(priv, &priv->rates); | 7572 | init_supported_rates(priv, &priv->rates); |
7162 | 7573 | ||
7163 | /* If we are currently associated, or trying to associate | 7574 | /* Network configuration changed -- force [re]association */ |
7164 | * then see if this is a new configuration (causing us to | 7575 | IPW_DEBUG_ASSOC("[re]association triggered due to mode change.\n"); |
7165 | * disassociate) */ | 7576 | if (!ipw_disassociate(priv)) { |
7166 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | ||
7167 | /* The resulting association will trigger | ||
7168 | * the new rates to be sent to the device */ | ||
7169 | IPW_DEBUG_ASSOC("Disassociating due to mode change.\n"); | ||
7170 | ipw_disassociate(priv); | ||
7171 | } else | ||
7172 | ipw_send_supported_rates(priv, &priv->rates); | 7577 | ipw_send_supported_rates(priv, &priv->rates); |
7578 | ipw_associate(priv); | ||
7579 | } | ||
7173 | 7580 | ||
7174 | /* Update the band LEDs */ | 7581 | /* Update the band LEDs */ |
7175 | ipw_led_band_on(priv); | 7582 | ipw_led_band_on(priv); |
@@ -7177,6 +7584,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, | |||
7177 | IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", | 7584 | IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", |
7178 | mode & IEEE_A ? 'a' : '.', | 7585 | mode & IEEE_A ? 'a' : '.', |
7179 | mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.'); | 7586 | mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.'); |
7587 | up(&priv->sem); | ||
7180 | return 0; | 7588 | return 0; |
7181 | } | 7589 | } |
7182 | 7590 | ||
@@ -7185,7 +7593,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, | |||
7185 | union iwreq_data *wrqu, char *extra) | 7593 | union iwreq_data *wrqu, char *extra) |
7186 | { | 7594 | { |
7187 | struct ipw_priv *priv = ieee80211_priv(dev); | 7595 | struct ipw_priv *priv = ieee80211_priv(dev); |
7188 | 7596 | down(&priv->sem); | |
7189 | switch (priv->ieee->mode) { | 7597 | switch (priv->ieee->mode) { |
7190 | case IEEE_A: | 7598 | case IEEE_A: |
7191 | strncpy(extra, "802.11a (1)", MAX_WX_STRING); | 7599 | strncpy(extra, "802.11a (1)", MAX_WX_STRING); |
@@ -7216,6 +7624,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, | |||
7216 | IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra); | 7624 | IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra); |
7217 | 7625 | ||
7218 | wrqu->data.length = strlen(extra) + 1; | 7626 | wrqu->data.length = strlen(extra) + 1; |
7627 | up(&priv->sem); | ||
7219 | 7628 | ||
7220 | return 0; | 7629 | return 0; |
7221 | } | 7630 | } |
@@ -7226,18 +7635,17 @@ static int ipw_wx_set_preamble(struct net_device *dev, | |||
7226 | { | 7635 | { |
7227 | struct ipw_priv *priv = ieee80211_priv(dev); | 7636 | struct ipw_priv *priv = ieee80211_priv(dev); |
7228 | int mode = *(int *)extra; | 7637 | int mode = *(int *)extra; |
7229 | 7638 | down(&priv->sem); | |
7230 | /* Switching from SHORT -> LONG requires a disassociation */ | 7639 | /* Switching from SHORT -> LONG requires a disassociation */ |
7231 | if (mode == 1) { | 7640 | if (mode == 1) { |
7232 | if (!(priv->config & CFG_PREAMBLE_LONG)) { | 7641 | if (!(priv->config & CFG_PREAMBLE_LONG)) { |
7233 | priv->config |= CFG_PREAMBLE_LONG; | 7642 | priv->config |= CFG_PREAMBLE_LONG; |
7234 | if (priv->status & | 7643 | |
7235 | (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 7644 | /* Network configuration changed -- force [re]association */ |
7236 | IPW_DEBUG_ASSOC | 7645 | IPW_DEBUG_ASSOC |
7237 | ("Disassociating due to preamble " | 7646 | ("[re]association triggered due to preamble change.\n"); |
7238 | "change.\n"); | 7647 | if (!ipw_disassociate(priv)) |
7239 | ipw_disassociate(priv); | 7648 | ipw_associate(priv); |
7240 | } | ||
7241 | } | 7649 | } |
7242 | goto done; | 7650 | goto done; |
7243 | } | 7651 | } |
@@ -7246,10 +7654,11 @@ static int ipw_wx_set_preamble(struct net_device *dev, | |||
7246 | priv->config &= ~CFG_PREAMBLE_LONG; | 7654 | priv->config &= ~CFG_PREAMBLE_LONG; |
7247 | goto done; | 7655 | goto done; |
7248 | } | 7656 | } |
7249 | 7657 | up(&priv->sem); | |
7250 | return -EINVAL; | 7658 | return -EINVAL; |
7251 | 7659 | ||
7252 | done: | 7660 | done: |
7661 | up(&priv->sem); | ||
7253 | return 0; | 7662 | return 0; |
7254 | } | 7663 | } |
7255 | 7664 | ||
@@ -7258,12 +7667,12 @@ static int ipw_wx_get_preamble(struct net_device *dev, | |||
7258 | union iwreq_data *wrqu, char *extra) | 7667 | union iwreq_data *wrqu, char *extra) |
7259 | { | 7668 | { |
7260 | struct ipw_priv *priv = ieee80211_priv(dev); | 7669 | struct ipw_priv *priv = ieee80211_priv(dev); |
7261 | 7670 | down(&priv->sem); | |
7262 | if (priv->config & CFG_PREAMBLE_LONG) | 7671 | if (priv->config & CFG_PREAMBLE_LONG) |
7263 | snprintf(wrqu->name, IFNAMSIZ, "long (1)"); | 7672 | snprintf(wrqu->name, IFNAMSIZ, "long (1)"); |
7264 | else | 7673 | else |
7265 | snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); | 7674 | snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); |
7266 | 7675 | up(&priv->sem); | |
7267 | return 0; | 7676 | return 0; |
7268 | } | 7677 | } |
7269 | 7678 | ||
@@ -7275,7 +7684,7 @@ static int ipw_wx_set_monitor(struct net_device *dev, | |||
7275 | struct ipw_priv *priv = ieee80211_priv(dev); | 7684 | struct ipw_priv *priv = ieee80211_priv(dev); |
7276 | int *parms = (int *)extra; | 7685 | int *parms = (int *)extra; |
7277 | int enable = (parms[0] > 0); | 7686 | int enable = (parms[0] > 0); |
7278 | 7687 | down(&priv->sem); | |
7279 | IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); | 7688 | IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); |
7280 | if (enable) { | 7689 | if (enable) { |
7281 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { | 7690 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { |
@@ -7285,11 +7694,14 @@ static int ipw_wx_set_monitor(struct net_device *dev, | |||
7285 | 7694 | ||
7286 | ipw_set_channel(priv, parms[1]); | 7695 | ipw_set_channel(priv, parms[1]); |
7287 | } else { | 7696 | } else { |
7288 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) | 7697 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { |
7698 | up(&priv->sem); | ||
7289 | return 0; | 7699 | return 0; |
7700 | } | ||
7290 | priv->net_dev->type = ARPHRD_ETHER; | 7701 | priv->net_dev->type = ARPHRD_ETHER; |
7291 | queue_work(priv->workqueue, &priv->adapter_restart); | 7702 | queue_work(priv->workqueue, &priv->adapter_restart); |
7292 | } | 7703 | } |
7704 | up(&priv->sem); | ||
7293 | return 0; | 7705 | return 0; |
7294 | } | 7706 | } |
7295 | 7707 | ||
@@ -7473,7 +7885,7 @@ static inline void init_sys_config(struct ipw_sys_config *sys_config) | |||
7473 | sys_config->dot11g_auto_detection = 0; | 7885 | sys_config->dot11g_auto_detection = 0; |
7474 | sys_config->enable_cts_to_self = 0; | 7886 | sys_config->enable_cts_to_self = 0; |
7475 | sys_config->bt_coexist_collision_thr = 0; | 7887 | sys_config->bt_coexist_collision_thr = 0; |
7476 | sys_config->pass_noise_stats_to_host = 0; //1 -- fix for 256 | 7888 | sys_config->pass_noise_stats_to_host = 1; //1 -- fix for 256 |
7477 | } | 7889 | } |
7478 | 7890 | ||
7479 | static int ipw_net_open(struct net_device *dev) | 7891 | static int ipw_net_open(struct net_device *dev) |
@@ -7481,9 +7893,11 @@ static int ipw_net_open(struct net_device *dev) | |||
7481 | struct ipw_priv *priv = ieee80211_priv(dev); | 7893 | struct ipw_priv *priv = ieee80211_priv(dev); |
7482 | IPW_DEBUG_INFO("dev->open\n"); | 7894 | IPW_DEBUG_INFO("dev->open\n"); |
7483 | /* we should be verifying the device is ready to be opened */ | 7895 | /* we should be verifying the device is ready to be opened */ |
7896 | down(&priv->sem); | ||
7484 | if (!(priv->status & STATUS_RF_KILL_MASK) && | 7897 | if (!(priv->status & STATUS_RF_KILL_MASK) && |
7485 | (priv->status & STATUS_ASSOCIATED)) | 7898 | (priv->status & STATUS_ASSOCIATED)) |
7486 | netif_start_queue(dev); | 7899 | netif_start_queue(dev); |
7900 | up(&priv->sem); | ||
7487 | return 0; | 7901 | return 0; |
7488 | } | 7902 | } |
7489 | 7903 | ||
@@ -7511,6 +7925,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) | |||
7511 | struct clx2_queue *q = &txq->q; | 7925 | struct clx2_queue *q = &txq->q; |
7512 | u8 id, hdr_len, unicast; | 7926 | u8 id, hdr_len, unicast; |
7513 | u16 remaining_bytes; | 7927 | u16 remaining_bytes; |
7928 | int fc; | ||
7514 | 7929 | ||
7515 | switch (priv->ieee->iw_mode) { | 7930 | switch (priv->ieee->iw_mode) { |
7516 | case IW_MODE_ADHOC: | 7931 | case IW_MODE_ADHOC: |
@@ -7562,6 +7977,9 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) | |||
7562 | if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE) | 7977 | if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE) |
7563 | tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE; | 7978 | tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE; |
7564 | 7979 | ||
7980 | fc = le16_to_cpu(hdr->frame_ctl); | ||
7981 | hdr->frame_ctl = cpu_to_le16(fc & ~IEEE80211_FCTL_MOREFRAGS); | ||
7982 | |||
7565 | memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); | 7983 | memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); |
7566 | 7984 | ||
7567 | /* payload */ | 7985 | /* payload */ |
@@ -7644,7 +8062,6 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, | |||
7644 | unsigned long flags; | 8062 | unsigned long flags; |
7645 | 8063 | ||
7646 | IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size); | 8064 | IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size); |
7647 | |||
7648 | spin_lock_irqsave(&priv->lock, flags); | 8065 | spin_lock_irqsave(&priv->lock, flags); |
7649 | 8066 | ||
7650 | if (!(priv->status & STATUS_ASSOCIATED)) { | 8067 | if (!(priv->status & STATUS_ASSOCIATED)) { |
@@ -7655,13 +8072,15 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, | |||
7655 | } | 8072 | } |
7656 | 8073 | ||
7657 | ipw_tx_skb(priv, txb); | 8074 | ipw_tx_skb(priv, txb); |
8075 | spin_unlock_irqrestore(&priv->lock, flags); | ||
7658 | ipw_led_activity_on(priv); | 8076 | ipw_led_activity_on(priv); |
7659 | 8077 | ||
7660 | spin_unlock_irqrestore(&priv->lock, flags); | 8078 | // up(&priv->sem); |
7661 | return 0; | 8079 | return 0; |
7662 | 8080 | ||
7663 | fail_unlock: | 8081 | fail_unlock: |
7664 | spin_unlock_irqrestore(&priv->lock, flags); | 8082 | spin_unlock_irqrestore(&priv->lock, flags); |
8083 | // up(&priv->sem); | ||
7665 | return 1; | 8084 | return 1; |
7666 | } | 8085 | } |
7667 | 8086 | ||
@@ -7685,11 +8104,13 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) | |||
7685 | struct sockaddr *addr = p; | 8104 | struct sockaddr *addr = p; |
7686 | if (!is_valid_ether_addr(addr->sa_data)) | 8105 | if (!is_valid_ether_addr(addr->sa_data)) |
7687 | return -EADDRNOTAVAIL; | 8106 | return -EADDRNOTAVAIL; |
8107 | down(&priv->sem); | ||
7688 | priv->config |= CFG_CUSTOM_MAC; | 8108 | priv->config |= CFG_CUSTOM_MAC; |
7689 | memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); | 8109 | memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); |
7690 | printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", | 8110 | printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", |
7691 | priv->net_dev->name, MAC_ARG(priv->mac_addr)); | 8111 | priv->net_dev->name, MAC_ARG(priv->mac_addr)); |
7692 | queue_work(priv->workqueue, &priv->adapter_restart); | 8112 | queue_work(priv->workqueue, &priv->adapter_restart); |
8113 | up(&priv->sem); | ||
7693 | return 0; | 8114 | return 0; |
7694 | } | 8115 | } |
7695 | 8116 | ||
@@ -7733,8 +8154,9 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev, | |||
7733 | 8154 | ||
7734 | if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE) | 8155 | if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE) |
7735 | return -EINVAL; | 8156 | return -EINVAL; |
7736 | 8157 | down(&p->sem); | |
7737 | memcpy(bytes, &((u8 *) p->eeprom)[eeprom->offset], eeprom->len); | 8158 | memcpy(bytes, &((u8 *) p->eeprom)[eeprom->offset], eeprom->len); |
8159 | up(&p->sem); | ||
7738 | return 0; | 8160 | return 0; |
7739 | } | 8161 | } |
7740 | 8162 | ||
@@ -7746,12 +8168,12 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev, | |||
7746 | 8168 | ||
7747 | if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE) | 8169 | if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE) |
7748 | return -EINVAL; | 8170 | return -EINVAL; |
7749 | 8171 | down(&p->sem); | |
7750 | memcpy(&((u8 *) p->eeprom)[eeprom->offset], bytes, eeprom->len); | 8172 | memcpy(&((u8 *) p->eeprom)[eeprom->offset], bytes, eeprom->len); |
7751 | for (i = IPW_EEPROM_DATA; | 8173 | for (i = IPW_EEPROM_DATA; |
7752 | i < IPW_EEPROM_DATA + CX2_EEPROM_IMAGE_SIZE; i++) | 8174 | i < IPW_EEPROM_DATA + CX2_EEPROM_IMAGE_SIZE; i++) |
7753 | ipw_write8(p, i, p->eeprom[i]); | 8175 | ipw_write8(p, i, p->eeprom[i]); |
7754 | 8176 | up(&p->sem); | |
7755 | return 0; | 8177 | return 0; |
7756 | } | 8178 | } |
7757 | 8179 | ||
@@ -7775,6 +8197,8 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | |||
7775 | 8197 | ||
7776 | if (!(priv->status & STATUS_INT_ENABLED)) { | 8198 | if (!(priv->status & STATUS_INT_ENABLED)) { |
7777 | /* Shared IRQ */ | 8199 | /* Shared IRQ */ |
8200 | // ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL); | ||
8201 | // return IRQ_HANDLED; | ||
7778 | goto none; | 8202 | goto none; |
7779 | } | 8203 | } |
7780 | 8204 | ||
@@ -7843,6 +8267,14 @@ static void ipw_rf_kill(void *adapter) | |||
7843 | spin_unlock_irqrestore(&priv->lock, flags); | 8267 | spin_unlock_irqrestore(&priv->lock, flags); |
7844 | } | 8268 | } |
7845 | 8269 | ||
8270 | static void ipw_bg_rf_kill(void *data) | ||
8271 | { | ||
8272 | struct ipw_priv *priv = data; | ||
8273 | down(&priv->sem); | ||
8274 | ipw_rf_kill(data); | ||
8275 | up(&priv->sem); | ||
8276 | } | ||
8277 | |||
7846 | void ipw_link_up(struct ipw_priv *priv) | 8278 | void ipw_link_up(struct ipw_priv *priv) |
7847 | { | 8279 | { |
7848 | netif_carrier_on(priv->net_dev); | 8280 | netif_carrier_on(priv->net_dev); |
@@ -7854,6 +8286,7 @@ void ipw_link_up(struct ipw_priv *priv) | |||
7854 | netif_start_queue(priv->net_dev); | 8286 | netif_start_queue(priv->net_dev); |
7855 | } | 8287 | } |
7856 | 8288 | ||
8289 | cancel_delayed_work(&priv->request_scan); | ||
7857 | ipw_reset_stats(priv); | 8290 | ipw_reset_stats(priv); |
7858 | /* Ensure the rate is updated immediately */ | 8291 | /* Ensure the rate is updated immediately */ |
7859 | priv->last_rate = ipw_get_current_rate(priv); | 8292 | priv->last_rate = ipw_get_current_rate(priv); |
@@ -7865,6 +8298,14 @@ void ipw_link_up(struct ipw_priv *priv) | |||
7865 | queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); | 8298 | queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); |
7866 | } | 8299 | } |
7867 | 8300 | ||
8301 | static void ipw_bg_link_up(void *data) | ||
8302 | { | ||
8303 | struct ipw_priv *priv = data; | ||
8304 | down(&priv->sem); | ||
8305 | ipw_link_up(data); | ||
8306 | up(&priv->sem); | ||
8307 | } | ||
8308 | |||
7868 | void ipw_link_down(struct ipw_priv *priv) | 8309 | void ipw_link_down(struct ipw_priv *priv) |
7869 | { | 8310 | { |
7870 | ipw_led_link_down(priv); | 8311 | ipw_led_link_down(priv); |
@@ -7883,6 +8324,14 @@ void ipw_link_down(struct ipw_priv *priv) | |||
7883 | queue_work(priv->workqueue, &priv->request_scan); | 8324 | queue_work(priv->workqueue, &priv->request_scan); |
7884 | } | 8325 | } |
7885 | 8326 | ||
8327 | static void ipw_bg_link_down(void *data) | ||
8328 | { | ||
8329 | struct ipw_priv *priv = data; | ||
8330 | down(&priv->sem); | ||
8331 | ipw_link_down(data); | ||
8332 | up(&priv->sem); | ||
8333 | } | ||
8334 | |||
7886 | static int ipw_setup_deferred_work(struct ipw_priv *priv) | 8335 | static int ipw_setup_deferred_work(struct ipw_priv *priv) |
7887 | { | 8336 | { |
7888 | int ret = 0; | 8337 | int ret = 0; |
@@ -7890,28 +8339,31 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) | |||
7890 | priv->workqueue = create_workqueue(DRV_NAME); | 8339 | priv->workqueue = create_workqueue(DRV_NAME); |
7891 | init_waitqueue_head(&priv->wait_command_queue); | 8340 | init_waitqueue_head(&priv->wait_command_queue); |
7892 | 8341 | ||
7893 | INIT_WORK(&priv->adhoc_check, ipw_adhoc_check, priv); | 8342 | INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv); |
7894 | INIT_WORK(&priv->associate, ipw_associate, priv); | 8343 | INIT_WORK(&priv->associate, ipw_bg_associate, priv); |
7895 | INIT_WORK(&priv->disassociate, ipw_disassociate, priv); | 8344 | INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv); |
7896 | INIT_WORK(&priv->rx_replenish, ipw_rx_queue_replenish, priv); | 8345 | INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv); |
7897 | INIT_WORK(&priv->adapter_restart, ipw_adapter_restart, priv); | 8346 | INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv); |
7898 | INIT_WORK(&priv->rf_kill, ipw_rf_kill, priv); | 8347 | INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv); |
7899 | INIT_WORK(&priv->up, (void (*)(void *))ipw_up, priv); | 8348 | INIT_WORK(&priv->up, (void (*)(void *))ipw_bg_up, priv); |
7900 | INIT_WORK(&priv->down, (void (*)(void *))ipw_down, priv); | 8349 | INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv); |
7901 | INIT_WORK(&priv->request_scan, | 8350 | INIT_WORK(&priv->request_scan, |
7902 | (void (*)(void *))ipw_request_scan, priv); | 8351 | (void (*)(void *))ipw_bg_request_scan, priv); |
7903 | INIT_WORK(&priv->gather_stats, | 8352 | INIT_WORK(&priv->gather_stats, |
7904 | (void (*)(void *))ipw_gather_stats, priv); | 8353 | (void (*)(void *))ipw_bg_gather_stats, priv); |
7905 | INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_abort_scan, priv); | 8354 | INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv); |
7906 | INIT_WORK(&priv->roam, ipw_roam, priv); | 8355 | INIT_WORK(&priv->roam, ipw_bg_roam, priv); |
7907 | INIT_WORK(&priv->scan_check, ipw_scan_check, priv); | 8356 | INIT_WORK(&priv->scan_check, ipw_bg_scan_check, priv); |
7908 | INIT_WORK(&priv->link_up, (void (*)(void *))ipw_link_up, priv); | 8357 | INIT_WORK(&priv->link_up, (void (*)(void *))ipw_bg_link_up, priv); |
7909 | INIT_WORK(&priv->link_down, (void (*)(void *))ipw_link_down, priv); | 8358 | INIT_WORK(&priv->link_down, (void (*)(void *))ipw_bg_link_down, priv); |
7910 | INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_led_link_on, priv); | 8359 | INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_bg_led_link_on, |
7911 | INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_led_link_off, | 8360 | priv); |
8361 | INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_bg_led_link_off, | ||
7912 | priv); | 8362 | priv); |
7913 | INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_led_activity_off, | 8363 | INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_bg_led_activity_off, |
7914 | priv); | 8364 | priv); |
8365 | INIT_WORK(&priv->merge_networks, | ||
8366 | (void (*)(void *))ipw_merge_adhoc_network, priv); | ||
7915 | 8367 | ||
7916 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | 8368 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) |
7917 | ipw_irq_tasklet, (unsigned long)priv); | 8369 | ipw_irq_tasklet, (unsigned long)priv); |
@@ -7924,7 +8376,7 @@ static void shim__set_security(struct net_device *dev, | |||
7924 | { | 8376 | { |
7925 | struct ipw_priv *priv = ieee80211_priv(dev); | 8377 | struct ipw_priv *priv = ieee80211_priv(dev); |
7926 | int i; | 8378 | int i; |
7927 | 8379 | down(&priv->sem); | |
7928 | for (i = 0; i < 4; i++) { | 8380 | for (i = 0; i < 4; i++) { |
7929 | if (sec->flags & (1 << i)) { | 8381 | if (sec->flags & (1 << i)) { |
7930 | priv->sec.key_sizes[i] = sec->key_sizes[i]; | 8382 | priv->sec.key_sizes[i] = sec->key_sizes[i]; |
@@ -7989,6 +8441,7 @@ static void shim__set_security(struct net_device *dev, | |||
7989 | ipw_disassociate(priv); | 8441 | ipw_disassociate(priv); |
7990 | } | 8442 | } |
7991 | #endif | 8443 | #endif |
8444 | up(&priv->sem); | ||
7992 | } | 8445 | } |
7993 | 8446 | ||
7994 | static int init_supported_rates(struct ipw_priv *priv, | 8447 | static int init_supported_rates(struct ipw_priv *priv, |
@@ -8054,6 +8507,11 @@ static int ipw_config(struct ipw_priv *priv) | |||
8054 | 8507 | ||
8055 | /* set basic system config settings */ | 8508 | /* set basic system config settings */ |
8056 | init_sys_config(&priv->sys_config); | 8509 | init_sys_config(&priv->sys_config); |
8510 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) | ||
8511 | priv->sys_config.answer_broadcast_ssid_probe = 1; | ||
8512 | else | ||
8513 | priv->sys_config.answer_broadcast_ssid_probe = 0; | ||
8514 | |||
8057 | if (ipw_send_system_config(priv, &priv->sys_config)) | 8515 | if (ipw_send_system_config(priv, &priv->sys_config)) |
8058 | goto error; | 8516 | goto error; |
8059 | 8517 | ||
@@ -8075,8 +8533,10 @@ static int ipw_config(struct ipw_priv *priv) | |||
8075 | goto error; | 8533 | goto error; |
8076 | 8534 | ||
8077 | /* If configured to try and auto-associate, kick off a scan */ | 8535 | /* If configured to try and auto-associate, kick off a scan */ |
8078 | if ((priv->config & CFG_ASSOCIATE) && ipw_request_scan(priv)) | 8536 | if ((priv->config & CFG_ASSOCIATE) && ipw_request_scan(priv)) { |
8537 | IPW_WARNING("error sending scan request\n"); | ||
8079 | goto error; | 8538 | goto error; |
8539 | } | ||
8080 | 8540 | ||
8081 | return 0; | 8541 | return 0; |
8082 | 8542 | ||
@@ -8106,8 +8566,9 @@ static int ipw_up(struct ipw_priv *priv) | |||
8106 | eeprom_parse_mac(priv, priv->mac_addr); | 8566 | eeprom_parse_mac(priv, priv->mac_addr); |
8107 | memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); | 8567 | memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); |
8108 | 8568 | ||
8109 | if (priv->status & STATUS_RF_KILL_MASK) | 8569 | if (priv->status & STATUS_RF_KILL_MASK) { |
8110 | return 0; | 8570 | return 0; |
8571 | } | ||
8111 | 8572 | ||
8112 | rc = ipw_config(priv); | 8573 | rc = ipw_config(priv); |
8113 | if (!rc) { | 8574 | if (!rc) { |
@@ -8115,12 +8576,11 @@ static int ipw_up(struct ipw_priv *priv) | |||
8115 | ipw_led_init(priv); | 8576 | ipw_led_init(priv); |
8116 | ipw_led_radio_on(priv); | 8577 | ipw_led_radio_on(priv); |
8117 | priv->notif_missed_beacons = 0; | 8578 | priv->notif_missed_beacons = 0; |
8579 | priv->status |= STATUS_INIT; | ||
8118 | return 0; | 8580 | return 0; |
8119 | } else { | ||
8120 | IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", | ||
8121 | rc); | ||
8122 | } | 8581 | } |
8123 | 8582 | ||
8583 | IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", rc); | ||
8124 | IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n", | 8584 | IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n", |
8125 | i, MAX_HW_RESTARTS); | 8585 | i, MAX_HW_RESTARTS); |
8126 | 8586 | ||
@@ -8132,13 +8592,22 @@ static int ipw_up(struct ipw_priv *priv) | |||
8132 | /* tried to restart and config the device for as long as our | 8592 | /* tried to restart and config the device for as long as our |
8133 | * patience could withstand */ | 8593 | * patience could withstand */ |
8134 | IPW_ERROR("Unable to initialize device after %d attempts.\n", i); | 8594 | IPW_ERROR("Unable to initialize device after %d attempts.\n", i); |
8595 | |||
8135 | return -EIO; | 8596 | return -EIO; |
8136 | } | 8597 | } |
8137 | 8598 | ||
8599 | static void ipw_bg_up(void *data) | ||
8600 | { | ||
8601 | struct ipw_priv *priv = data; | ||
8602 | down(&priv->sem); | ||
8603 | ipw_up(data); | ||
8604 | up(&priv->sem); | ||
8605 | } | ||
8606 | |||
8138 | static void ipw_down(struct ipw_priv *priv) | 8607 | static void ipw_down(struct ipw_priv *priv) |
8139 | { | 8608 | { |
8140 | /* Attempt to disable the card */ | ||
8141 | #if 0 | 8609 | #if 0 |
8610 | /* Attempt to disable the card */ | ||
8142 | ipw_send_card_disable(priv, 0); | 8611 | ipw_send_card_disable(priv, 0); |
8143 | #endif | 8612 | #endif |
8144 | 8613 | ||
@@ -8147,7 +8616,6 @@ static void ipw_down(struct ipw_priv *priv) | |||
8147 | 8616 | ||
8148 | /* Clear all bits but the RF Kill */ | 8617 | /* Clear all bits but the RF Kill */ |
8149 | priv->status &= STATUS_RF_KILL_MASK; | 8618 | priv->status &= STATUS_RF_KILL_MASK; |
8150 | |||
8151 | netif_carrier_off(priv->net_dev); | 8619 | netif_carrier_off(priv->net_dev); |
8152 | netif_stop_queue(priv->net_dev); | 8620 | netif_stop_queue(priv->net_dev); |
8153 | 8621 | ||
@@ -8156,6 +8624,14 @@ static void ipw_down(struct ipw_priv *priv) | |||
8156 | ipw_led_radio_off(priv); | 8624 | ipw_led_radio_off(priv); |
8157 | } | 8625 | } |
8158 | 8626 | ||
8627 | static void ipw_bg_down(void *data) | ||
8628 | { | ||
8629 | struct ipw_priv *priv = data; | ||
8630 | down(&priv->sem); | ||
8631 | ipw_down(data); | ||
8632 | up(&priv->sem); | ||
8633 | } | ||
8634 | |||
8159 | static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 8635 | static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
8160 | { | 8636 | { |
8161 | struct iwreq *wrq = (struct iwreq *)rq; | 8637 | struct iwreq *wrq = (struct iwreq *)rq; |
@@ -8176,21 +8652,26 @@ static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
8176 | static int ipw_net_init(struct net_device *dev) | 8652 | static int ipw_net_init(struct net_device *dev) |
8177 | { | 8653 | { |
8178 | struct ipw_priv *priv = ieee80211_priv(dev); | 8654 | struct ipw_priv *priv = ieee80211_priv(dev); |
8179 | 8655 | down(&priv->sem); | |
8180 | if (priv->status & STATUS_RF_KILL_SW) { | 8656 | if (priv->status & STATUS_RF_KILL_SW) { |
8181 | IPW_WARNING("Radio disabled by module parameter.\n"); | 8657 | IPW_WARNING("Radio disabled by module parameter.\n"); |
8658 | up(&priv->sem); | ||
8182 | return 0; | 8659 | return 0; |
8183 | } else if (rf_kill_active(priv)) { | 8660 | } else if (rf_kill_active(priv)) { |
8184 | IPW_WARNING("Radio Frequency Kill Switch is On:\n" | 8661 | IPW_WARNING("Radio Frequency Kill Switch is On:\n" |
8185 | "Kill switch must be turned off for " | 8662 | "Kill switch must be turned off for " |
8186 | "wireless networking to work.\n"); | 8663 | "wireless networking to work.\n"); |
8187 | queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); | 8664 | queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); |
8665 | up(&priv->sem); | ||
8188 | return 0; | 8666 | return 0; |
8189 | } | 8667 | } |
8190 | 8668 | ||
8191 | if (ipw_up(priv)) | 8669 | if (ipw_up(priv)) { |
8670 | up(&priv->sem); | ||
8192 | return -EIO; | 8671 | return -EIO; |
8672 | } | ||
8193 | 8673 | ||
8674 | up(&priv->sem); | ||
8194 | return 0; | 8675 | return 0; |
8195 | } | 8676 | } |
8196 | 8677 | ||
@@ -8275,6 +8756,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
8275 | #endif | 8756 | #endif |
8276 | spin_lock_init(&priv->lock); | 8757 | spin_lock_init(&priv->lock); |
8277 | 8758 | ||
8759 | init_MUTEX(&priv->sem); | ||
8278 | if (pci_enable_device(pdev)) { | 8760 | if (pci_enable_device(pdev)) { |
8279 | err = -ENODEV; | 8761 | err = -ENODEV; |
8280 | goto out_free_ieee80211; | 8762 | goto out_free_ieee80211; |
@@ -8416,9 +8898,14 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
8416 | ipw_wx_data.spy_data = &priv->ieee->spy_data; | 8898 | ipw_wx_data.spy_data = &priv->ieee->spy_data; |
8417 | ipw_wx_data.ieee80211 = priv->ieee; | 8899 | ipw_wx_data.ieee80211 = priv->ieee; |
8418 | 8900 | ||
8901 | down(&priv->sem); | ||
8902 | |||
8419 | priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; | 8903 | priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; |
8420 | priv->ieee->set_security = shim__set_security; | 8904 | priv->ieee->set_security = shim__set_security; |
8421 | 8905 | ||
8906 | priv->ieee->perfect_rssi = -20; | ||
8907 | priv->ieee->worst_rssi = -85; | ||
8908 | |||
8422 | net_dev->open = ipw_net_open; | 8909 | net_dev->open = ipw_net_open; |
8423 | net_dev->stop = ipw_net_stop; | 8910 | net_dev->stop = ipw_net_stop; |
8424 | net_dev->init = ipw_net_init; | 8911 | net_dev->init = ipw_net_init; |
@@ -8438,15 +8925,16 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
8438 | err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group); | 8925 | err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group); |
8439 | if (err) { | 8926 | if (err) { |
8440 | IPW_ERROR("failed to create sysfs device attributes\n"); | 8927 | IPW_ERROR("failed to create sysfs device attributes\n"); |
8928 | up(&priv->sem); | ||
8441 | goto out_release_irq; | 8929 | goto out_release_irq; |
8442 | } | 8930 | } |
8443 | 8931 | ||
8932 | up(&priv->sem); | ||
8444 | err = register_netdev(net_dev); | 8933 | err = register_netdev(net_dev); |
8445 | if (err) { | 8934 | if (err) { |
8446 | IPW_ERROR("failed to register network device\n"); | 8935 | IPW_ERROR("failed to register network device\n"); |
8447 | goto out_remove_sysfs; | 8936 | goto out_remove_sysfs; |
8448 | } | 8937 | } |
8449 | |||
8450 | return 0; | 8938 | return 0; |
8451 | 8939 | ||
8452 | out_remove_sysfs: | 8940 | out_remove_sysfs: |
@@ -8623,8 +9111,7 @@ module_param(auto_create, int, 0444); | |||
8623 | MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); | 9111 | MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); |
8624 | 9112 | ||
8625 | module_param(led, int, 0444); | 9113 | module_param(led, int, 0444); |
8626 | MODULE_PARM_DESC(auto_create, | 9114 | MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)\n"); |
8627 | "enable led control on some systems (default 0 off)\n"); | ||
8628 | 9115 | ||
8629 | module_param(debug, int, 0444); | 9116 | module_param(debug, int, 0444); |
8630 | MODULE_PARM_DESC(debug, "debug output mask"); | 9117 | MODULE_PARM_DESC(debug, "debug output mask"); |
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 1b339cb7a522..243b8ea14140 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h | |||
@@ -936,8 +936,8 @@ struct ipw_priv { | |||
936 | struct ieee80211_device *ieee; | 936 | struct ieee80211_device *ieee; |
937 | struct ieee80211_security sec; | 937 | struct ieee80211_security sec; |
938 | 938 | ||
939 | /* spinlock */ | ||
940 | spinlock_t lock; | 939 | spinlock_t lock; |
940 | struct semaphore sem; | ||
941 | 941 | ||
942 | /* basic pci-network driver stuff */ | 942 | /* basic pci-network driver stuff */ |
943 | struct pci_dev *pci_dev; | 943 | struct pci_dev *pci_dev; |
@@ -1068,6 +1068,7 @@ struct ipw_priv { | |||
1068 | struct work_struct led_link_on; | 1068 | struct work_struct led_link_on; |
1069 | struct work_struct led_link_off; | 1069 | struct work_struct led_link_off; |
1070 | struct work_struct led_act_off; | 1070 | struct work_struct led_act_off; |
1071 | struct work_struct merge_networks; | ||
1071 | 1072 | ||
1072 | #define IPW_2200BG 1 | 1073 | #define IPW_2200BG 1 |
1073 | #define IPW_2915ABG 2 | 1074 | #define IPW_2915ABG 2 |
@@ -1160,6 +1161,7 @@ do { if (ipw_debug_level & (level)) \ | |||
1160 | #define IPW_DL_TRACE (1<<28) | 1161 | #define IPW_DL_TRACE (1<<28) |
1161 | 1162 | ||
1162 | #define IPW_DL_STATS (1<<29) | 1163 | #define IPW_DL_STATS (1<<29) |
1164 | #define IPW_DL_MERGE (1<<30) | ||
1163 | 1165 | ||
1164 | #define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) | 1166 | #define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) |
1165 | #define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) | 1167 | #define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) |
@@ -1187,6 +1189,7 @@ do { if (ipw_debug_level & (level)) \ | |||
1187 | #define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) | 1189 | #define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) |
1188 | #define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) | 1190 | #define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) |
1189 | #define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a) | 1191 | #define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a) |
1192 | #define IPW_DEBUG_MERGE(f, a...) IPW_DEBUG(IPW_DL_MERGE, f, ## a) | ||
1190 | 1193 | ||
1191 | #include <linux/ctype.h> | 1194 | #include <linux/ctype.h> |
1192 | 1195 | ||